1
0
Fork 0

Compare commits

...

621 Commits

Author SHA1 Message Date
Peter Nelson 86996bc7f8
Change: Automatically push/pop colours when formatting a sub-string.
Reverts 226a44bf86.

This universally prevents the sub-string from changing colours in the outer string.
2025-07-20 15:29:42 +01:00
Jonathan G Rennison 821784004d Fix: [Linkgraph] Incorrect NodeID to StationID conversion for EraseFlows 2025-07-20 16:07:11 +02:00
Jonathan G Rennison f0447d59d4 Codechange: Use StationID as StationIDStack Titem type 2025-07-20 16:06:03 +02:00
Jonathan G Rennison cbdd358ae8 Codechange: Allow SmallStack Titem type to be non-structural 2025-07-20 16:06:03 +02:00
Peter Nelson 2cdd50f40e
Fix 03f5f7145f: Wrong colour used when string POP_COLOURs back to initial colour. (#14468)
Fixing ellipsis colour broke the PUSH_COLOUR/POP_COLOUR system, reverting to the last used colour instead of the initial colour.
2025-07-20 14:30:18 +01:00
Peter Nelson 56942a15c7 Add: Industry accepted and waiting history graphs.
Records amount of cargo accepted, and a rolling average of the waiting amount.

Average waiting samples the waiting amount once per day for each industry, spread out over an economy day.
2025-07-20 14:03:54 +01:00
Peter Nelson 5eeda026a4 Codechange: Allow unused graph ranges to be masked. 2025-07-20 14:03:54 +01:00
Peter Nelson edc5b8ea1f
Fix #14464: Invalid string parameter in scenario editor when unable to build industry. (#14465)
Resolved by removing the Build Industry command callback. This was used to display an error message in the scenario editor, however an error is already automatically displayed.
2025-07-20 14:03:29 +01:00
Peter Nelson a8650c6b06
Codechange: Make SpriteCacheCtrlFlags an enum bit set. (#14462)
Due to header dependencies, this requires types to split from the spritecache header.
2025-07-19 23:49:15 +01:00
Peter Nelson 7bb4940ebd
Codechange: Use unique_ptr for all pointers in script instance. (#14339)
Removes manual memory management with new/delete.
2025-07-19 09:29:30 +01:00
translators b8e56cd05d Update: Translations from eints
chinese (traditional): 3 changes by KogentaSan
chinese (simplified): 1 change by ahyangyi
2025-07-19 04:43:14 +00:00
Peter Nelson df5237e721
Fix: Vehicle liveries did not update when switching company. (#14456)
Vehicle liveries must be refreshed if "Show vehicle-type specific liveries" is set to "Own company".
2025-07-18 23:43:07 +00:00
Peter Nelson 03f5f7145f
Fix f6e78a480d: Truncation ellipsis always drawn in initial colour. (#14451)
Truncation ellipsis is now a layouted line, so we can no longer rely on implicitly using the last set colour.
2025-07-18 18:24:19 +01:00
Peter Nelson 0dc40877fd
Codechange: Initialise/reset font cache with FontSizes bitset. (#14448)
Instead of choosing either "Normal/Small/Large" or "Monospace", use an EnumBitSet to allow any combination.
2025-07-18 18:23:28 +01:00
Jonathan G Rennison 03672ed8eb
Fix: EngineImageType mismatch between sizing and drawing in preview window (#14455) 2025-07-18 07:02:46 -04:00
Loïc Guilloux 1b01a0636c
Fix #14362, 4b677e8256: Don't crash old scripts doing silly instantiation (#14394) 2025-07-17 13:30:33 +02:00
nikolas bccbd64037
Fix: GL error typo (#14376) 2025-07-17 07:18:35 +01:00
Ivan Pravdin 434163aa31
Fix #14277: Aircraft can land when Zeppeliner in the runway (#14317) 2025-07-17 07:26:57 +02:00
translators 55605ae8f2 Update: Translations from eints
english (au): 1 change by krysclarke
catalan: 1 change by J0anJosep
portuguese: 8 changes by jcteotonio
2025-07-17 04:45:55 +00:00
Jonathan G Rennison 7f792e9c5f
Codefix: Spelling error in name of GetGRFStringTextStackParameters (#14447) 2025-07-16 09:21:25 -04:00
translators 6b6caa6fa8 Update: Translations from eints
chinese (traditional): 1 change by KogentaSan
greek: 1 change by gh658804
hungarian: 1 change by vargaviktor
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
catalan: 49 changes by J0anJosep
portuguese: 2 changes by jcteotonio
portuguese (brazilian): 1 change by pasantoro
polish: 1 change by pAter-exe
2025-07-16 04:46:46 +00:00
Peter Nelson 67e56391c7
Fix #8167: No error sub-message when trying to clear protected buildings. (#14444) 2025-07-14 23:23:15 +01:00
Peter Nelson e015e3ecc3
Codefix 3fde611012: AirportMovingDataFlag should be `enum class` (#14435)
`AirportMovingDataFlag` was changed to use `enum class` naming style, but wasn't actually changed to be `enum class`.
2025-07-14 23:22:51 +01:00
Henry Wilson 8330957a4d Codechange: Remove manual memory management from IcuStringIterator 2025-07-14 23:55:24 +02:00
Peter Nelson 9ce2aca949 Codechange: Get/pass ScriptStorage by reference instead of pointer. 2025-07-14 19:19:29 +01:00
Peter Nelson 55098a2f2e Codechange: Get/pass engine by reference instead of pointer. 2025-07-14 19:19:29 +01:00
Peter Nelson 7ff0c67f77 Codechange: Get/pass script controller by reference instead of pointer. 2025-07-14 19:19:29 +01:00
Peter Nelson b2de1ff66f
Fix #14433: Broken road stop drawing due to incorrect modes conversion. (#14434)
The mask was treated as a single RoadStopDrawMode instead of a RoadStopDrawModes bitset.
2025-07-14 17:25:53 +01:00
Loïc Guilloux fc924161ab
Fix 0455627d: Don't draw timetable panel if no orders (#14441) 2025-07-14 14:18:54 +00:00
Peter Nelson 61a299bc99
Codechange: Use SpriteID as GlyphID for SpriteFontCache. (#14439)
This reduces the amount of lookups in the character map as rendering a cached layout no longer needs to do so.
2025-07-14 13:28:10 +01:00
Peter Nelson 7546c1acab
Codefix f220ed179d: GetUnicodeGlyph takes a unicode character. (#14438)
Previous change erroneously changed type to GlyphID, based on naming. It should actually be char32_t.
2025-07-14 08:01:42 +00:00
Peter Nelson a6143eea21
Codechange: Include more relevant headers for script_storage. (#14437) 2025-07-14 07:49:50 +01:00
Peter Nelson 1d38cbafcb Codechange: Use unique_ptr for ScriptInfo instances.
Replaces raw pointers, slightly.
2025-07-14 00:10:14 +01:00
Peter Nelson 992d58d799 Codechange: Pass ScriptInfo by reference to IsSameScript. 2025-07-14 00:10:14 +01:00
Peter Nelson 8f34b7a821 Codechange: Keep Squirrel engine in unique_ptr. 2025-07-14 00:10:14 +01:00
Peter Nelson bf6d0c4934
Codechange: Don't pre-fill font metrics when loading fonts. (#14436)
Each font cache implementation sets its own metrics based on the loaded font, so there is no need to pre-fill with (unscaled, invalid) default metrics.
2025-07-13 23:38:31 +01:00
Michael Lutz 3c4fb21a5e
Fix: [Win32] Link failure with newer Windows SDK version due to WinRT changes. (#14432) 2025-07-13 22:34:32 +01:00
translators baced00e9f Update: Translations from eints
spanish (mexican): 1 change by absay
english (us): 1 change by 2TallTyler
galician: 10 changes by pvillaverde
dutch: 1 change by Afoklala
portuguese: 10 changes by jcteotonio
2025-07-13 04:45:12 +00:00
translators aaf5d39b15 Update: Translations from eints
english (au): 1 change by krysclarke
chinese (traditional): 1 change by KogentaSan
chinese (simplified): 1 change by WenSimEHRP
korean: 1 change by telk5093
greek: 1 change by gh658804
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
portuguese: 1 change by azulcosta
portuguese (brazilian): 1 change by pasantoro
polish: 1 change by pAter-exe
2025-07-11 04:45:38 +00:00
Richard Wheeler 7db135099a
Fix: Scale graph gridlines and axes with GUI scale (#12131) 2025-07-10 00:05:48 +01:00
Peter Nelson 290144c5c9 Fix #14396: Industry production graph showed zero instead of N/A.
Record the number of valid history records per industry so that the graph avoids showing values which are not present as zero.
2025-07-09 23:02:58 +01:00
Peter Nelson 9b55ad5b8d Codechange: Generic type and container for history statistics. 2025-07-09 23:02:58 +01:00
Peter Nelson f6e78a480d
Change: Make truncation ellipsis translatable. (#14417) 2025-07-09 22:55:43 +01:00
Tyler Trahan 259830777c
Fix #14375: When loading config, validate timekeeping mode and minutes per year (#14405) 2025-07-09 16:04:38 -04:00
Tyler Trahan 753905ae2d
Fix #14377: Make house picker window remember house protection state when closed (#14406) 2025-07-09 14:18:19 +00:00
Peter Nelson d2ee2add28
Codechange: Remove ZOOM_LVL_GUI macro. (#14423) 2025-07-09 11:05:06 +01:00
translators 8de32c4509 Update: Translations from eints
portuguese: 7 changes by jcteotonio
2025-07-09 04:45:29 +00:00
Peter Nelson 77b572619a
Codechange: Make use of ZoomLevels range iteration. (#14422) 2025-07-08 14:00:12 +01:00
Peter Nelson b21c8a3450
Codechange: Simplify test for bridges above bridge ramps. (#14421) 2025-07-08 13:55:36 +01:00
translators 6d86c760c6 Update: Translations from eints
hungarian: 9 changes by vargaviktor
2025-07-08 04:43:02 +00:00
translators d44e693b25 Update: Translations from eints
norwegian (bokmal): 17 changes by eriksorngard
spanish (mexican): 6 changes by absay
english (us): 21 changes by 2TallTyler
2025-07-07 04:45:34 +00:00
translators b0ea6c0974 Update: Translations from eints
chinese (traditional): 6 changes by KogentaSan
chinese (simplified): 6 changes by WenSimEHRP
2025-07-06 04:44:01 +00:00
Peter Nelson 84e9e106c1
Codefix: SpriteFontCache was never deleted. (#14414) 2025-07-05 13:22:45 +01:00
translators ebd984d894 Update: Translations from eints
english (au): 3 changes by krysclarke
korean: 6 changes by telk5093
greek: 3 changes by gh658804
russian: 3 changes by Ln-Wolf
dutch: 6 changes by Afoklala
portuguese: 4 changes by jcteotonio
portuguese (brazilian): 3 changes by pasantoro
2025-07-05 04:43:09 +00:00
translators f23845805a Update: Translations from eints
english (au): 6 changes by krysclarke
greek: 7 changes by gh658804
russian: 6 changes by Ln-Wolf
finnish: 25 changes by hpiirai
portuguese: 19 changes by jcteotonio
portuguese (brazilian): 6 changes by pasantoro
polish: 6 changes by pAter-exe
2025-07-04 04:42:38 +00:00
Loïc Guilloux 655291facb
Fix #14385: [Strgen] Don't count parameters more than one time (#14413) 2025-07-04 01:10:50 +02:00
Peter Nelson 16b0371c1b
Codechange: Remove owner from CargoPayment. (#14411)
Owner can instead be looked up from the CargoPayment's vehicle.

This reduces the size of each CargoPayment slightly.
2025-07-03 23:11:12 +01:00
Heikki Piirainen febba930b0 Fix: Inconsistent capitalization in game settings 2025-07-03 17:11:51 +02:00
translators bf07751ee7 Update: Translations from eints
spanish (mexican): 12 changes by absay
portuguese: 1 change by jcteotonio
2025-07-03 04:44:02 +00:00
Tyler Trahan e578668a93
Fix #14360: Don't reuse strings for Low/Medium/High setting values (#14409) 2025-07-02 06:09:39 -04:00
translators 226b098c55 Update: Translations from eints
portuguese: 17 changes by jcteotonio
2025-07-02 04:42:46 +00:00
Peter Nelson 0391eec189
Change: Improve sprite ellipsis appearance. (#14404)
Make spacing more consistent with periods.
2025-07-01 17:34:26 +01:00
translators b84b641ed9 Update: Translations from eints
hungarian: 7 changes by vargaviktor
2025-07-01 04:45:31 +00:00
Peter Nelson 4fe6adb2dd
Fix c2d4098afa: Crash when accessing unconfigurable badge feature. (#14403)
Some features support badges but do not have a way to configure them. Accessing these features could crash the game.
2025-06-30 21:45:08 +01:00
Peter Nelson 36d7e09369
Fix: Include sort button width in content list header minimal size. (#14402) 2025-06-30 20:40:26 +01:00
Peter Nelson 42a9d27fd9
Fix: Don't draw truncation ellipsis if it's too wide. (#14401) 2025-06-30 20:40:04 +01:00
Peter Nelson 80d2194511
Fix: Don't include ellipsis width in RTL truncation offset. (#14400)
This caused the right-most glyphs to be truncated.
2025-06-30 10:03:24 +01:00
translators 7c33a67e7b Update: Translations from eints
galician: 30 changes by pvillaverde
danish: 6 changes by bscargo
2025-06-30 04:44:29 +00:00
translators 9bcf1cf29b Update: Translations from eints
korean: 8 changes by telk5093
polish: 3 changes by pAter-exe
2025-06-29 04:45:43 +00:00
Peter Nelson 4b6d409ee8
Codefix: Out-of-range cargo type passed to a string affected remaining parameters. (#14398)
When the string codes CARGO_TINY, CARGO_SHORT or CARGO_LONG encountered an out-of-range string, they did not read the extra amount parameter. This leads to later parameters being used in the wrong place.

Change the order of operation so that all parameters for these string codes are always read, even if the cargo type is not valid.
2025-06-28 21:50:36 +01:00
translators a37ad181ff Update: Translations from eints
dutch: 12 changes by Afoklala
polish: 12 changes by pAter-exe
2025-06-28 04:42:40 +00:00
Peter Nelson 20ed5be905
Codechange: Use FontSizeToName() instead of switch block. (#14395) 2025-06-27 20:38:39 +00:00
translators f41ad372a3 Update: Translations from eints
chinese (traditional): 1 change by KogentaSan
2025-06-27 04:42:22 +00:00
Peter Nelson bd2430dc94 Codechange: Use FlatSet to avoid trying to add variant parents multiple times. 2025-06-26 08:33:34 +01:00
Peter Nelson 1ddc03b916 Codechange: Give FlatSet insert() a return value.
This now returns an iterator, and whether an insert was performed.

Allows the caller to know if the item was already in the FlatSet without explicitly checking first.
2025-06-26 08:33:34 +01:00
translators 1ff12b6e74 Update: Translations from eints
english (au): 8 changes by krysclarke
chinese (traditional): 23 changes by KogentaSan
chinese (simplified): 12 changes by WenSimEHRP
greek: 8 changes by gh658804
russian: 6 changes by Ln-Wolf
finnish: 8 changes by hpiirai
portuguese: 9 changes by jcteotonio
portuguese (brazilian): 8 changes by pasantoro
2025-06-26 04:43:34 +00:00
Peter Nelson d5ebd20110
Fix 319caef58f: Buildings with non-zero subtile offsets broken in house picker. (#14390)
Partially reverts 319caef58f. Conversion of subtile position was originally correct.
2025-06-25 17:33:15 +00:00
translators b3c96a7785 Update: Translations from eints
english (au): 4 changes by krysclarke
norwegian (bokmal): 4 changes by eriksorngard
chinese (traditional): 4 changes by KogentaSan
korean: 4 changes by telk5093
greek: 4 changes by gh658804
hungarian: 4 changes by vargaviktor
russian: 4 changes by Ln-Wolf
finnish: 4 changes by hpiirai
portuguese: 4 changes by jcteotonio
portuguese (brazilian): 4 changes by pasantoro
2025-06-25 04:42:43 +00:00
Peter Nelson 8f01ae675e
Revert 0853c1979b: Button to toggle showing advanced signal types (#9617) (#14219) 2025-06-24 20:18:08 +02:00
Peter Nelson a46a3a97f3
Change: New company face definition system and UI. (#14319)
Bits used by company faces are now defined by a variable system instead of being hardcoded, allowing future expansion.

The four face types covering gender and skin colour are now separate face styles with their own definitions.
2025-06-24 07:59:49 +01:00
translators ebc74c8905 Update: Translations from eints 2025-06-24 04:43:09 +00:00
Jonathan G Rennison e436b32468 Codechange: Remove now unused sprite cache memory error strings 2025-06-23 21:22:37 +01:00
Peter Nelson 7744f49a9e Change: Simplify sprite cache memory management
* Remove custom allocator
* Use std::unique_ptr for sprite data
* Perform LRU cache eviction in a single pass
2025-06-23 21:22:37 +01:00
Peter Nelson 1d67094863
Add: Buttons to change picker preview image height. (#14373)
Adjusted height is remembered per picker type, but not saved.
2025-06-23 08:24:49 +01:00
Peter Nelson 8901f9adca
Fix #14361: Removing a badge filter did not clear it. (#14379) 2025-06-23 08:24:03 +01:00
translators c15568be5f Update: Translations from eints
ukrainian: 20 changes by StepanIvasyn
latvian: 13 changes by lexuslatvia
2025-06-22 04:43:50 +00:00
Patric Stout 3571f77d46
Codechange: typo in GoG's workflow (#14386) 2025-06-21 09:25:39 +00:00
dependabot[bot] 1b2a3b0cb1
Upgrade: Bump Apple-Actions/import-codesign-certs in the actions group (#13945)
Bumps the actions group with 1 update: [Apple-Actions/import-codesign-certs](https://github.com/apple-actions/import-codesign-certs).

Updates `Apple-Actions/import-codesign-certs` from 3 to 5
- [Release notes](https://github.com/apple-actions/import-codesign-certs/releases)
- [Commits](https://github.com/apple-actions/import-codesign-certs/compare/v3...v5)

---
updated-dependencies:
- dependency-name: Apple-Actions/import-codesign-certs
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-21 09:18:32 +00:00
Peter Nelson 5766ba51d7
Codefix: Clean up incorrect indentation for multi-line comments. (#14383) 2025-06-20 19:01:44 +01:00
translators a927925996 Update: Translations from eints
portuguese: 13 changes by jcteotonio
2025-06-20 04:42:53 +00:00
translators de6e420917 Update: Translations from eints
ukrainian: 11 changes by StepanIvasyn
portuguese: 18 changes by jcteotonio
2025-06-19 04:43:06 +00:00
Adam Zmuda 9238f508eb
Fix #14081: Check if removed item is a savegame (#14371) 2025-06-18 10:05:18 +02:00
translators 7aa4e7fc58 Update: Translations from eints
ukrainian: 12 changes by StepanIvasyn
portuguese: 8 changes by jcteotonio
2025-06-18 04:43:22 +00:00
Peter Nelson c882ad5142
Fix: Allow object picker to resize if there are no classes. (#14372) 2025-06-17 19:04:34 +01:00
Peter Nelson e4cf6ca0ba
Fix: Mis-sized widgets due to missing widget fill. (#14370)
In most places where we calculate and set widget resize step we neglect
to set widget fill step to match. Initial widget sizing uses fill step
instead of resize step, which means the initial size may not be a
multiple of the resize step as intended. In particular this will cause
WWT_MATRIX to be misrendered.

Whether or not this matters depends on the widget type being resized and
the window layout, however for consistency always set fill step to the
same as resize step when calculating.
2025-06-17 17:40:11 +01:00
Peter Nelson 4144865c73 Change: Tweak layout of music player widgets.
This removes some magic numbers and gets rid of spacers.
2025-06-17 08:54:08 +01:00
Peter Nelson 7ec78e94db Fix: Don't include height of blank text in frame and inset widgets. 2025-06-17 08:54:08 +01:00
translators dd826ea49c Update: Translations from eints
spanish: 13 changes by Unely
portuguese: 30 changes by jcteotonio
2025-06-17 04:41:57 +00:00
Peter Nelson 009b68caeb
Codechange: Use toolbar minimal sizing with intro menu buttons. (#14368)
The intro menu buttons use toolbar icons, so use SetToolbarMinimalSize() on them for consistency.
2025-06-17 01:12:39 +01:00
Colin Caine 5f8e04457e
Codechange: Use default OnHotkey handler for focusing editboxes (#14358) 2025-06-16 22:25:54 +02:00
Henry 56bc391763
Codechange: Remove manual memory management of AIScannerInfo::info_dummy (#14338)
Co-authored-by: Henry Wilson <henry@henryandlizzy.uk>
2025-06-16 10:30:22 +01:00
translators ea410cfe85 Update: Translations from eints
chinese (traditional): 4 changes by KogentaSan
chinese (simplified): 69 changes by WenSimEHRP
ukrainian: 57 changes by StepanIvasyn
portuguese: 35 changes by jcteotonio
2025-06-16 04:43:21 +00:00
Henry c71515e790
Codechange: Remove manual memory management from CountArticulatedParts (#14336)
Co-authored-by: Henry Wilson <henry@henryandlizzy.uk>
2025-06-15 21:38:00 +01:00
Peter Nelson cdd555edd5
Codechange: Use vector with unique_ptr instead of linked-list for base set lists. (#14332) 2025-06-15 21:32:29 +01:00
Michael Lutz e163aab892
Fix: Train path reservations on different railtypes could join leading to train crashes. (#14366)
This could happen if the compatibility between the railtypes was not symmetric. If for
example a reservation of a first train ended at a railtype transition with an already present
reservation on the other side, a reversing train could end up crashing with the first train.
2025-06-15 22:09:04 +02:00
translators 98b488f366 Update: Translations from eints
chinese (traditional): 3 changes by KogentaSan
chinese (simplified): 108 changes by WenSimEHRP
ukrainian: 21 changes by StepanIvasyn
dutch: 9 changes by Afoklala
portuguese: 177 changes by jcteotonio
2025-06-15 04:42:32 +00:00
Loïc Guilloux d0b56022d8
Fix #14362, 4b677e8256: Class with non static methods may have a default constructor (#14363) 2025-06-14 23:39:22 +02:00
Peter Nelson 1cd0391926
Fix #14356, ff7eb996e6: Incorrect sprite group chosen for stations and road stops. (#14359) 2025-06-14 13:38:45 +01:00
glx22 8e3acbfa84 Codechange: Deduplicate DefSQClass::DefSQ[Static]Method() 2025-06-14 12:41:39 +02:00
glx22 90e21bc713 Codechange: Remove useless SQConstruct parameters 2025-06-14 12:41:39 +02:00
glx22 4b677e8256 Codechange: Don't export default constructors 2025-06-14 12:41:39 +02:00
glx22 ccffbb4142 Codechange: Remove manual param count for constructors too 2025-06-14 12:41:39 +02:00
glx22 6d601e2eb1 Codechange: Use more descriptive variable names 2025-06-14 12:41:39 +02:00
translators a1786fa1f4 Update: Translations from eints
norwegian (bokmal): 13 changes by eriksorngard
ukrainian: 28 changes by StepanIvasyn
portuguese: 16 changes by jcteotonio
polish: 1 change by pAter-exe
2025-06-13 04:42:21 +00:00
Jonathan G Rennison d3e4e07daa Codechange: Remove ReferenceThroughBaseContainer 2025-06-12 18:50:49 +01:00
Jonathan G Rennison 63f1c2aa3a Codechange: Use TypedIndexContainer for typed index containers
Instead of ReferenceThroughBaseContainer
2025-06-12 18:50:49 +01:00
Jonathan G Rennison d0e49a297f Codechange: Add TypedIndexContainer adapter type
This is equivalent in functionality to ReferenceThroughBaseContainer,
except only for the correct index type, instead of any type matching
ConvertibleThroughBase.
The also serves to unambiguously document the index type at the
point of definition of the container.
2025-06-12 18:50:49 +01:00
Peter Nelson 401ebed03a
Add: Show and sort online content version in list. (#14355) 2025-06-12 18:27:16 +01:00
translators b012d9e3dc Update: Translations from eints
danish: 18 changes by bscargo
portuguese: 23 changes by jcteotonio
2025-06-12 04:42:39 +00:00
Peter Nelson 28cc0079f2
Codechange: Create ScriptAllocator with make_unique instead of new. (#14340) 2025-06-11 23:28:08 +01:00
Peter Nelson b2d69ae606
Codechange: Use AutoRelease to simplify cleanup after FontConfig calls. (#14354) 2025-06-11 21:24:31 +01:00
Peter Nelson 9c16603da6
Codechange: Add AutoRelease helper to use function as unique_ptr deleter. (#14353)
This allows passing the function as a template parameter instead of requiring a custom deleter functor.
2025-06-11 20:13:49 +01:00
translators f8776b0a6f Update: Translations from eints
hungarian: 9 changes by vargaviktor
finnish: 13 changes by hpiirai
ukrainian: 1 change by imlystyi
tamil: 2 changes by merni-ns
lithuanian: 1 change by khamper
spanish: 22 changes by Unely
portuguese: 46 changes by jcteotonio
2025-06-11 04:42:30 +00:00
Peter Nelson f2318c35db
Fix 0455627d16: Order backups were no longer created when selling vehicles. (#14352) 2025-06-10 18:03:05 +01:00
Peter Nelson c702e05517
Codechange: Replace C-casts for FontConfig with helper functions. (#14349)
Add `ToFcString()` and `FromFcString()` to remove C-style casts and make reinterpret_casts safer and clearer.
2025-06-10 17:11:22 +01:00
Peter Nelson 8f5ac84a3d
Fix 20738865f0: Remove colour codes from Game Options strings. (#14348)
When merging the game options and settings windows, colour codes were removed from strings. This change didn't get propagated to all translations.
2025-06-10 17:10:57 +01:00
translators 8c90be8c9f Update: Translations from eints
english (au): 9 changes by krysclarke
spanish (mexican): 10 changes by absay
english (us): 9 changes by 2TallTyler
korean: 13 changes by telk5093
lithuanian: 3 changes by khamper
portuguese: 13 changes by jcteotonio
polish: 9 changes by pAter-exe
2025-06-10 04:42:12 +00:00
Peter Nelson 4f18c18735
Fix: Remove U+200C characters from Lithuanian translation. (#14347)
This character prevents OpenTTD Sans being used.
2025-06-09 11:53:31 +00:00
translators 3908df5fbe Update: Translations from eints
chinese (traditional): 9 changes by KogentaSan
greek: 9 changes by gh658804
russian: 9 changes by Ln-Wolf
portuguese (brazilian): 9 changes by pasantoro
2025-06-09 04:43:26 +00:00
SamuXarick ac8b236885
Fix: [Script] Make ScriptOrder functions aware of road waypoints (#13419) 2025-06-08 16:49:36 -04:00
SamuXarick 484f18f987
Codechange: Code style changes to AI/GS GUI files (#13665) 2025-06-08 16:48:36 -04:00
SamuXarick 893a75f2c0
Codechange: Iterate with VehiclesOnTile when attaching a just bought wagon to a locomotive (#14284) 2025-06-08 16:45:58 -04:00
Peter Nelson de660cba02
Change: Consistent toolbar sizes with dedicated NWidgetParts. (#14344)
Add SetToolbarSpacerMinimalSize() and SetToolbarMinimalSize() NWidgetParts and use to make toolbar button sizes consistent.
2025-06-08 18:13:47 +00:00
Peter Nelson 7c9c2aec49
Codechange: Use vehicle tile hash to search for free wagons. (#14343)
Avoids iterating the vehicle pool.
2025-06-08 19:07:43 +01:00
translators 4b18622c4e Update: Translations from eints
chinese (traditional): 4 changes by KogentaSan
english (us): 4 changes by 2TallTyler
french: 4 changes by ottdfevr
2025-06-08 04:43:18 +00:00
Peter Nelson 2f725d1e85 Add: Hover on graph legend to highlight line. 2025-06-07 15:50:25 +01:00
Peter Nelson 10841ea3fd Codechange: Add constant for common blink interval. 2025-06-07 15:50:25 +01:00
Peter Nelson ecafbf884e
Add: Allow separate expansion of town buildings and roads in scenario editor. (#14341) 2025-06-07 13:56:43 +00:00
translators 6b5cde463a Update: Translations from eints
english (au): 4 changes by krysclarke
spanish (mexican): 3 changes by absay
greek: 4 changes by gh658804
hungarian: 4 changes by vargaviktor
russian: 5 changes by Ln-Wolf
dutch: 4 changes by Afoklala
portuguese (brazilian): 4 changes by pasantoro
polish: 4 changes by pAter-exe
2025-06-07 04:40:06 +00:00
Loïc Guilloux 9339b8270c
Fix: Wrong error message about script Save() returned value (#14334) 2025-06-06 19:01:50 +02:00
Peter Nelson a6de925ba6
Fix #14333, 20d83677eb: Incorrect change from index to range iteration. (#14335) 2025-06-06 16:57:26 +00:00
glx22 938acbe6ef Add: [Script] Cloning ScriptList 2025-06-05 22:37:33 +02:00
glx22 7200e7f509 Add: [Script] Framework for cloning selected ScriptObject 2025-06-05 22:37:33 +02:00
Jonathan G Rennison 7dcc932d44
Fix: Drag drop line position when dragging NewGRF from file to active panel (#14316) 2025-06-05 14:09:51 -04:00
Peter Nelson 48764b0fed Add: Badge dropdown filters to picker window. 2025-06-05 17:55:24 +01:00
Peter Nelson 7b60e5ccad Add: Badge dropdown filters to build vehicle window. 2025-06-05 17:55:24 +01:00
Peter Nelson 25f1c97bea Change: Add badge dropdown filters and configuration. 2025-06-05 17:55:24 +01:00
Peter Nelson 308ce39747 Codechange: Add DropDownUnselectable component.
This component makes a drop down item unselectable, as it says on the tin.
2025-06-05 17:55:24 +01:00
Peter Nelson 82f5af7ecd Codechange: Allow all widget types to have a WidgetID index. 2025-06-05 17:55:24 +01:00
glx22 31fbb17c5b Codechange: Replace ScriptObject::[SG]etAllowDoCommand with ScriptObject::DisableDoCommandScope 2025-06-05 01:39:40 +02:00
glx22 4beb23af30 Codechange: TicToc can now accumulate and output every tick 2025-06-04 23:59:06 +02:00
glx22 fca75fd06a Codechange: Use brace counting to detect end of class in squirrel-exporter 2025-06-04 19:48:27 +02:00
glx22 6482e16564 Codechange: Deduplicate namespace opening in squirrel-exporter 2025-06-04 19:48:27 +02:00
glx22 e0d8158957 Codechange: Don't use literal tabs in squirrel-exporter 2025-06-04 19:48:27 +02:00
Owen Rudge b0dbe631b3 Codechange: [CI] Azure Code Signing has been rebranded 'Trusted Signing' 2025-06-04 09:16:18 +01:00
Peter Nelson 2e78c24ba3
Codefix: Use bitset .None() or .Any() instead of comparing against an empty bitset. (#14327) 2025-06-04 07:31:44 +01:00
translators 8f10f9fb5a Update: Translations from eints
finnish: 1 change by hpiirai
2025-06-04 04:43:00 +00:00
Peter Nelson 5bf31a431e
Fix 4c8f1b0f81: Hidden-by-facility station signs were not ignored when handling clicks. (#14326) 2025-06-03 20:53:53 +00:00
Loïc Guilloux 9e8fc8da48
Fix: [Script] SQOpsLimiter had no effect for native valuator/filter (#14322) 2025-06-03 14:05:29 +02:00
Peter Nelson ea0b3983a5 Codechange: Deduplicate common parts of graph windows with cargo legends.
This unifies handling on the cargo selected to avoid having to rewrite it for every cargo graph window.
2025-06-02 17:40:39 +01:00
Peter Nelson 43d57a6b7e Codefix 5c45738613: Rename CompanyGraphWindow to BaseCompanyGraphWindow.
This makes it clearer that it isn't a final graph window.
2025-06-02 17:40:39 +01:00
translators 6d0dd90e20 Update: Translations from eints
korean: 2 changes by telk5093
portuguese: 2 changes by jcteotonio
2025-06-02 04:43:26 +00:00
Peter Nelson b7b2b57805
Fix bd1a3fe0b7: Crash if loading compatibility scripts fails. (#14318) 2025-05-31 19:59:23 +01:00
Peter Nelson 4ab48f34f5
Fix 5664b1e2f6: Upgrade button in NewGRF window no longer worked. (#14315) 2025-05-31 08:20:55 +00:00
translators 621c031307 Update: Translations from eints
dutch: 4 changes by Afoklala
2025-05-31 04:39:26 +00:00
Loïc Guilloux 2cd3c8db86
Codechange: [Script] Don't report multiple errors on valuator/filter failure (#14303) 2025-05-30 14:38:41 +02:00
translators 10c159a79f Update: Translations from eints
norwegian (bokmal): 4 changes by eriksorngard
korean: 4 changes by telk5093
2025-05-29 04:47:48 +00:00
Peter Nelson c233e5ee2c Codechange: Tweak layouts of graph windows to reduce spacers. 2025-05-28 18:40:33 +01:00
Peter Nelson 5c45738613 Codechange: Improve inheritance of graph windows.
BaseGraphWindow contains parts that are only relevant to company-series data -- these are moved to a separate class.
2025-05-28 18:40:33 +01:00
translators 3aca5d62a8 Update: Translations from eints
spanish (mexican): 4 changes by absay
chinese (simplified): 4 changes by WenSimEHRP
hungarian: 5 changes by vargaviktor
french: 27 changes by glx22
polish: 4 changes by pAter-exe
2025-05-28 04:47:09 +00:00
Peter Nelson 7c9393e822
Codechange: Remove terminator from airport tile lists. (#14306) 2025-05-27 20:23:59 +01:00
translators 808af15975 Update: Translations from eints
english (au): 4 changes by krysclarke
chinese (traditional): 5 changes by KogentaSan
english (us): 5 changes by 2TallTyler
greek: 4 changes by gh658804
russian: 4 changes by Ln-Wolf
finnish: 4 changes by hpiirai
latvian: 6 changes by lexuslatvia
portuguese: 4 changes by jcteotonio
portuguese (brazilian): 4 changes by pasantoro
2025-05-27 04:48:27 +00:00
Peter Nelson e2d066e5d3
Codefix: Effect vehicles don't use v->tile, so shouldn't be in the vehicle tile hash. (#14302) 2025-05-26 21:45:46 +01:00
translators e23a591a1e Update: Translations from eints
galician: 10 changes by pvillaverde
turkish: 20 changes by BeratSJ
latvian: 2 changes by lexuslatvia
2025-05-26 04:49:25 +00:00
Peter Nelson b042e7a439
Codefix: Prefer `static inline const` keyword order. (#14301) 2025-05-25 20:32:56 +01:00
Peter Nelson 948ceb3b17 Add: Button to configure badges in build picker window. 2025-05-25 09:13:05 +01:00
Peter Nelson f28dc3cca4 Add: Button to configure badges in build vehicle window. 2025-05-25 09:13:05 +01:00
Peter Nelson c2d4098afa Add: Configuration of NewGRF badges. 2025-05-25 09:13:05 +01:00
Peter Nelson daef052329 Add: Generic "configure list/view" vertical ellipsis icon. 2025-05-25 09:13:05 +01:00
Peter Nelson 29970fb496 Codechange: Add DropDownToggle component. 2025-05-25 09:13:05 +01:00
Peter Nelson 6e90b828c6 Codechange: Add CentreTo Rect method. 2025-05-25 09:13:05 +01:00
Peter Nelson c213218b66 Codechange: Pass click state to Dropdown Draw() function.
This allows drawing to change depending on last click position.
2025-05-25 09:13:05 +01:00
Peter Nelson 984d864c72 Codechange: Add OnClick handler for dropdown items.
This allows each dropdown item to indicate if something different should happen depending on where in the item was clicked.
2025-05-25 09:13:05 +01:00
Peter Nelson 04e07dff84 Codechange: Add Up/Down buttons, to fit in with the settings-button style. 2025-05-25 09:13:05 +01:00
translators b82e32c360 Update: Translations from eints
norwegian (bokmal): 1 change by eriksorngard
spanish (mexican): 1 change by absay
chinese (simplified): 1 change by WenSimEHRP
korean: 1 change by telk5093
danish: 68 changes by bscargo
2025-05-25 04:48:20 +00:00
Loïc Guilloux 5e765a2787
Codechange: [CMake] Use ".sq.hpp" instead of ".hpp.sq" for API exports (#14297) 2025-05-24 22:38:37 +02:00
Kuhnovic 34c0b09764
Codechange: Removed T prefix from water region related types. (#14290) 2025-05-24 18:12:16 +02:00
Loïc Guilloux fea120a710
Fix #14295, 0455627d16: v->cur_implicit_order_index is never INVALID_VEH_ORDER_ID (#14296) 2025-05-24 13:53:51 +00:00
translators c366e6a48e Update: Translations from eints
chinese (simplified): 1 change by WenSimEHRP
dutch: 1 change by Afoklala
2025-05-24 04:44:57 +00:00
Peter Nelson b42abfbefc
Fix 0455627d16: Incorrect script order position mapping. (#14294) 2025-05-23 19:55:22 +01:00
Kuhnovic 180ec6505b
Codechange: Use strong types for water regions. (#14289) 2025-05-23 20:54:42 +02:00
Peter Nelson 0455627d16
Codechange: Move ownership of Orders to OrderList. (#13948)
Removes the orders pool, and orders are now stored directly in each OrderList.

Iterating orders now no longer needs to traverse a linked-list, all orders in an OrderList are sequential.
2025-05-23 10:36:28 +01:00
Peter Nelson 7344dfe651 Change: Reflow Textfile window content incrementally.
This avoids a stall when reflowing a long text file with some truetype fonts.
2025-05-23 07:42:10 +01:00
Peter Nelson 46b745a06a Codechange: Use a helper method to test if text file window is wrapped. 2025-05-23 07:42:10 +01:00
Peter Nelson 940071a5f2 Codechange: Add alternating iterator to take elements from middle of range. 2025-05-23 07:42:10 +01:00
Peter Nelson 780c26237f Codechange: Add OnScrollbarScroll window event, called when a scrollbar position changes. 2025-05-23 07:42:10 +01:00
translators 321f7e8683 Update: Translations from eints
swedish: 3 changes by joeax910
2025-05-23 04:45:57 +00:00
Peter Nelson 1064309ecf
Change: Don't measure group name widths in company livery window. (#14291)
Measuring the name width did not also take account of indentation levels so didn't prevent cropping, and the window can be resized anyway.

This avoids a potential bottleneck due to layouting group names if there are a lot of groups present.
2025-05-22 22:57:50 +01:00
SamuXarick 5fef32bde7
Change: [Script] Move GSStation::GetOwner to GSBaseStation::GetOwner (#13406)
* Add: [Script] GSBaseStation::GetOwner

Added method for Game Scripts to retrieve the owner of a basestation.

* Cleanup: [Script] Remove ScriptStation::GetOwner

Due to class inheritance, GSStation::GetOwner and GSWaypoint::GetOwner can both reach GetOwner defined at GSBaseStation.
2025-05-22 13:47:04 +02:00
translators 467f832c2f Update: Translations from eints
english (au): 1 change by krysclarke
chinese (traditional): 10 changes by KogentaSan
greek: 1 change by gh658804
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
latvian: 1 change by lexuslatvia
portuguese: 1 change by jcteotonio
portuguese (brazilian): 1 change by pasantoro
polish: 10 changes by pAter-exe
2025-05-22 04:47:11 +00:00
Peter Nelson 5fe6578f64
Codechange: Improve performance of exclusive preview engine test. (#14270)
Check group statistics to test if a company has built an exclusive preview engine.

This improves performance by avoiding iterating the vehicle pool.
2025-05-21 21:19:38 +01:00
Peter Nelson 9f190aa534 Codechange: Use group's children list to improve performance of group UI. 2025-05-21 19:50:07 +01:00
Peter Nelson 000a79c093 Codechange: Improve performance of evaluating group hierarchy.
Store a list of child groups in each group, to avoid having to iterate the group pool to find its children.
2025-05-21 19:50:07 +01:00
SamuXarick 8f3f25de4b
Codefix: Missing 'this->' in VehiclesNearTileXY::Iterator::Iterator (#14288) 2025-05-21 20:28:47 +02:00
Peter Nelson 1d8db2223f
Fix #14234, 5aa4ad5135: Crash due to unexpected NUL char in string. (#14235)
Gracefully handle an unexpected NUL character in non-debug builds.
2025-05-21 18:47:04 +01:00
translators 82876c25e0 Update: Translations from eints 2025-05-21 04:46:46 +00:00
Peter Nelson a2addf0fe7
Fix: Clear rail vehicle flipped flag if reverse probability callback returns false. (#14281)
This now distinguishes between not-flipped and callback not implemented.
2025-05-20 23:03:55 +01:00
Peter Nelson acf594a7b7
Fix #14271, 7fd0e6c27d: Crash due to incorrect parameter index in string. (#14272) 2025-05-20 23:03:27 +01:00
Loïc Guilloux 4b1b2a4310
Change: [Script] Don't allow scripts to instantiate ScriptEvent (#14276) 2025-05-20 15:37:05 +02:00
frosch 2926179d02 Fix: Restore the behaviour when entering numbers in query windows: clamp integers out of range to the maximum valid value. 2025-05-20 12:57:30 +02:00
frosch c1389c77b2 Codechange: ParseInteger optionally clamps out-of-range values, instead of treating them as invalid. 2025-05-20 12:57:30 +02:00
translators ecadf1b322 Update: Translations from eints
hungarian: 4 changes by meskobalazs
2025-05-20 04:46:13 +00:00
Peter Nelson ce83f583bc
Codechange: Use EnumBitSet for VehicleRailFlags. (#14280) 2025-05-19 18:56:45 +01:00
Peter Nelson 77d6f6c69f
Codechange: Make ContentType::State an enum class. (#14279) 2025-05-19 17:11:28 +01:00
SamuXarick ad3a34e9ef
Add: [Script] ScriptVehicleList_Waypoint (#13456)
Creates a list of vehicles that have orders to a given waypoint.
2025-05-19 14:48:17 +02:00
Loïc Guilloux 1b0fd0e6fd
Fix b2c57123: [Script] Conversion from ScriptEvent to ScriptEventCompanyTown subclasses (#14274) 2025-05-18 15:40:47 +02:00
translators 9bbc525e53 Update: Translations from eints
catalan: 17 changes by J0anJosep
2025-05-18 04:50:09 +00:00
Peter Nelson 940a7127f8
Fix f8bdc1e612: Empty first parameter of EncodedString was skipped. (#14273)
This would place the remaining parameters one position too early.
2025-05-17 22:55:48 +00:00
translators 617169c1c9 Update: Translations from eints
norwegian (bokmal): 2 changes by eriksorngard
english (us): 9 changes by 2TallTyler
romanian: 3 changes by The-Bober
dutch: 2 changes by Afoklala
2025-05-17 04:44:32 +00:00
translators 521d0465d9 Update: Translations from eints
korean: 2 changes by telk5093
hungarian: 26 changes by meskobalazs
2025-05-16 04:47:27 +00:00
translators 6c84dd1f32 Update: Translations from eints
persian: 371 changes by realsepehrz
romanian: 49 changes by The-Bober
portuguese: 2 changes by azulcosta
2025-05-15 04:46:38 +00:00
Peter Nelson c8a336f760 Codechange: Move GetNthSetBit() to BaseBitSet.
This now returns the correct type, or std::nullopt instead of -1.
2025-05-14 07:22:12 +01:00
Peter Nelson c50ee282f9 Codechange: EnumBitSet bits can be iterated directly. 2025-05-14 07:22:12 +01:00
Peter Nelson 66c16a1d1f Codechange: Add Count() method to BaseBitSet. 2025-05-14 07:22:12 +01:00
translators ecc3438519 Update: Translations from eints
polish: 2 changes by pAter-exe
2025-05-14 04:46:05 +00:00
Loïc Guilloux c16d5f3a8d
Change: [Script] ScriptVehicleList_Station accepts an optional VehicleType parameter (#14260) 2025-05-13 16:41:23 +02:00
Peter Nelson 87fa1e41d5 Codechange: Use std::byte for sound buffers. 2025-05-13 14:51:17 +01:00
Peter Nelson 5585363407 Codechange: Use std::byte for glyph sprite buffer. 2025-05-13 14:51:17 +01:00
translators c718858999 Update: Translations from eints
english (au): 2 changes by krysclarke
chinese (traditional): 2 changes by KogentaSan
spanish (mexican): 2 changes by absay
chinese (simplified): 11 changes by WenSimEHRP
greek: 2 changes by gh658804
hungarian: 2 changes by vargaviktor
persian: 17 changes by realsepehrz
russian: 2 changes by lexuslatvia
finnish: 4 changes by hpiirai
latvian: 2 changes by lexuslatvia
portuguese (brazilian): 2 changes by pasantoro
2025-05-13 04:47:36 +00:00
Peter Nelson 156f98ba06
Fix #14256, dfd9fbf873: Company finance windows not updated when paused. (#14258)
Refresh company finance windows via a WindowTimer instead of in game loop.

As the invalidation affects multiple windows this is a global timer instead of window-specific.
2025-05-13 01:23:27 +01:00
Peter Nelson bc778545b3
Fix 0829604b4f: Dragging of selected order was still not possible. (#14259)
Check click_count condition earlier so that drag and drop is activated.
2025-05-13 01:22:58 +01:00
Peter Nelson 431e57d087
Fix 0ce30d05c8: Replacing a dropdown list could reposition it partially off-screen. (#14261) 2025-05-13 01:22:45 +01:00
Peter Nelson d37d4c18b5
Change: Remove Apply button from NewGRF config window when unneeded. (#14254)
When configuring NewGRFs outside of a game, the changes are always applied when the window is closed, even if the Apply button is not used.

The Apply button only needs appear during a game when changes are not automatically applied.
2025-05-13 01:22:23 +01:00
Jonathan G Rennison d107b7c8c0 Fix 3cf9b159: Incorrect tile colour in smallmap for snowy MP_CLEAR tiles in vegetation mode
See: #13659
2025-05-12 19:04:43 +02:00
Peter Nelson d9247fa1a0
Change: Remove extra close buttons from some windows. (#14124)
All windows have an X button to close it, so remove the redundant close buttons.
2025-05-12 14:54:44 +01:00
frosch a62081d79e
Fix #14251: Out-of-bounds writes via TextRefStack. (#14255) 2025-05-12 13:59:33 +02:00
Peter Nelson 0aacd7acb3
Codechange: Use GrfSpecFeature type instead of uint8_t. (#14253) 2025-05-12 08:44:39 +01:00
translators 2516c435b7 Update: Translations from eints
swedish: 9 changes by joeax910
2025-05-12 04:47:40 +00:00
Rubidium 568b70e556 Codechange: replace memmove with std::move(_backwards) 2025-05-11 21:51:57 +02:00
Rubidium 3cd040ffe9 Codechange: unify moving of pixels in the blitters 2025-05-11 21:51:57 +02:00
Peter Nelson b38527ca05
Change: Move OpenTTD version to intro viewport. (#14233)
This stops the length of the game version from affecting the main menu.
2025-05-11 20:01:22 +01:00
Rubidium 03116ea878 Codechange: remove now unused cpp_sizeof 2025-05-11 13:48:23 +02:00
Rubidium 02d8ae018c Codechange: simplify getting the value of a NewGRF property 2025-05-11 13:48:23 +02:00
Rubidium f2b48bad79 Codechange: remove last (hidden) users of memset 2025-05-11 06:07:01 +02:00
frosch c037722cb5
Fix 51a7edd: NewGRF debug sprite picker was broken. (#14246) 2025-05-10 20:27:43 +02:00
Rubidium a48a5f0cc6 Codechange: replace memcpy with std::copy_n 2025-05-10 16:50:58 +02:00
Loïc Guilloux a45f23686d
Fix #14241, 6e10584: Invalid string parameters in subsidies list window (#14243) 2025-05-09 18:08:17 +02:00
Rubidium f8aceb6c37 Codechange: use value initialisation over memset 2025-05-09 17:20:41 +02:00
Rubidium 7981fcb297 Codechange: use std::fill_n over memset 2025-05-09 17:20:41 +02:00
Rubidium 92bd78dd25 Codechange: use std::ranges::fill over memset 2025-05-09 17:20:41 +02:00
Rubidium 96873dee63 Codechange: use std::array.fill over memset 2025-05-09 17:20:41 +02:00
frosch 228f9ca941
Fix #13854: 40bpp-anim blitter recolouring failed for 32bpp pixels without mask channel. (#14242) 2025-05-09 17:16:29 +02:00
frosch a277cb2b4c Change: [NewGRF] Increase the textstack for all callbacks to 16 registers. 2025-05-09 12:39:11 +02:00
frosch c6fa5022cb Add: [NewGRF] All callbacks returning D0xx strings, have now the option to return any string id via register 0x100. 2025-05-09 12:39:11 +02:00
frosch 84bc78fd8f Add: [NewGRF] Special value 0x7FFE for VarAction2 results specifying 'return calculated result'. 2025-05-09 12:38:58 +02:00
frosch 9d32087236 Add: [NewGRF] Special value 0x7FFF for Action2 references specifying explicit 'callback/sprite-resolving failed'. 2025-05-09 12:38:58 +02:00
translators b1cdf5024f Update: Translations from eints
spanish (mexican): 7 changes by absay
2025-05-09 04:46:47 +00:00
Peter Nelson ae1f469aac
Fix #14234, 16b4e73: Skip PLURAL data if parameter is invalid. (#14236) 2025-05-08 09:06:56 +01:00
glx22 1d18b4a80b Codechange: remove core/mem_func.hpp 2025-05-08 09:33:18 +02:00
glx22 aba5e1258e Codechange: use assignment over MemCpyT 2025-05-08 09:33:18 +02:00
glx22 6356311fbc Codechange: use std::copy_n over MemCpyT 2025-05-08 09:33:18 +02:00
glx22 a013f81120 Codechange: use std::array's fill over memset 2025-05-08 09:33:18 +02:00
glx22 82244779eb Codechange: use C++ initialisation over MemSetT 2025-05-08 09:33:18 +02:00
translators 6680169251 Update: Translations from eints 2025-05-08 04:46:44 +00:00
Peter Nelson 2feba80fd7 Codechange: Codestyle fixes for elrail code. 2025-05-07 20:34:33 +01:00
Peter Nelson 4a8dd494ee Codechange: Don't abbreviate TileLocationGroup type name. 2025-05-07 20:34:33 +01:00
frosch d00196cd65 Change: Rearrange buttons in the intro screen, remove unnecessary ones. 2025-05-07 18:41:48 +02:00
frosch 4111ce2698 Add: WWT_IMGTEXTBTN, WWT_PUSHIMGTEXTBTN 2025-05-07 18:41:48 +02:00
Peter Nelson a7019b859c Codechange: Use DiagDirections when checking for flat buildable tiles. 2025-05-07 17:31:29 +01:00
Peter Nelson aa9e5b38cd Codechange: Use DiagDirections when drawing level crossings. 2025-05-07 17:31:29 +01:00
Peter Nelson 1ac9f24f38 Codechange: Use (Diag)Directions when drawing catenary. 2025-05-07 17:31:29 +01:00
Peter Nelson 87544eff0c Codechange: Use DiagDirections to collect rail fence data. 2025-05-07 17:31:29 +01:00
Peter Nelson 1cbc4da054 Codechange: Use Directions for water flooding data. 2025-05-07 17:31:29 +01:00
Peter Nelson 968bb8961e Codechange: Add Directions and DiagDirections EnumBitSets. 2025-05-07 17:31:29 +01:00
Peter Nelson e0dbbbb032 Codechange: Add Reset() and missing &=/|= operators for BaseBitSet. 2025-05-07 17:31:29 +01:00
Peter Nelson c4d033967b
Codechange: Remove some unnecessary includes from network files. (#14226) 2025-05-07 16:46:14 +01:00
frosch 22fedca77e Codechange: Integrate ResolverObject::ResetState() into DoResolve(), no need to call it manually. 2025-05-06 22:24:41 +02:00
frosch f8c928ed98 Codechange: Make temporary storage a member of ResolverObject. 2025-05-06 22:24:41 +02:00
frosch eb9bbb2456 Codechange: Remove direct access to temporary storage from TextRefStack. 2025-05-06 22:24:41 +02:00
frosch 6faa667644 Codechange: Remove global GetRegister(), instead return 100+ registers directly from GetXxxCallback(). 2025-05-06 22:24:41 +02:00
frosch f59cf73b88 Codechange: Access temporary storage through ResolverObject during sprite layout preprocessing. 2025-05-06 22:24:41 +02:00
frosch 85be7a4d92 Codechange: Access temporary storage through ResolverObject during Resolve. 2025-05-06 22:24:41 +02:00
frosch 99d7a775ad Codechange: Make GetRegister return a signed integer, matching the underlying TemporaryStorageArray. 2025-05-06 22:24:41 +02:00
frosch 74030a63e6 Codechange: Move SpriteLayoutProcessor's operations closer to the ResolverObject. 2025-05-06 22:24:41 +02:00
Rubidium 0ffdc86a2c Codechange: use std::ranges::equal over memcmp 2025-05-06 21:29:21 +02:00
Rubidium 89deb3876f Codechange: use fstream to compare file equality 2025-05-06 21:29:21 +02:00
frosch cd7ac64f9d
Codefix: Fix compilation with DEBUG_DUMP_COMMANDS. (#14228) 2025-05-06 21:11:30 +02:00
frosch 592cc49b62 Codechange: Turn _grow_town_result into a local variable in GrowTownAtRoad. 2025-05-06 20:58:17 +02:00
frosch 5af877d12d Codechange: Do not assign _grow_town_result in GrowTownInTile, instead return the new value. 2025-05-06 20:58:17 +02:00
frosch 22af391064 Codechange: Move _grow_town_result out of GrowTownWithExtraHouse, GrowTownWithRoad, GrowTownWithBridge and GrowTownWithTunnel. 2025-05-06 20:58:17 +02:00
Rubidium d70aeb72a7 Codechange: C++ initialise LanguageHeaderPack 2025-05-06 20:03:35 +02:00
Rubidium 8f1e94c546 Codechange: use C++ initialisation over MemSetT 2025-05-06 20:03:35 +02:00
Rubidium cc51b29234 Codechange: use std::fill_n/copy_n over MemSetT/MemCpyT 2025-05-06 20:03:35 +02:00
Rubidium 0d922c9d62 Codechange: use std::array's fill over memset 2025-05-06 20:03:35 +02:00
Rubidium 4c1cd4fe4c Codefix: remove unused mem_func includes 2025-05-06 20:03:35 +02:00
Peter Nelson 9735fbbaa1 Codechange: Use LRUCache for layouted LineCache.
This avoids needing to manually manage the size of the cache.
2025-05-06 18:09:00 +01:00
Peter Nelson 8c4f8af66e Codechange: Move std::unique_ptr out of LRUCache implementation.
This is an implementation detail of how OpenGLSprites are stored.
2025-05-06 18:09:00 +01:00
frosch 8bbfbd0347 Codechange: Move spritelayout preprocessing to a separate class, which owns the heap allocations involved. 2025-05-06 18:30:42 +02:00
frosch d9c43e7fda Codechange: Make TileLayoutSpriteGroup::ProcessRegisters return a DrawTileSpriteSpan on the stack, instead of a reference to a global. 2025-05-06 18:30:42 +02:00
frosch 51a7edd941 Codechange: Remove _input_events_this_tick. 2025-05-06 18:29:41 +02:00
frosch 42f9312f71 Codechange: Make station variable cache a member of StationScopeResolver. 2025-05-06 18:29:41 +02:00
frosch b20b6da937 Codechange: The compiler ensures static variables are initialised only once, no need to track that manually. 2025-05-06 18:29:41 +02:00
frosch 75a775e59d Codechange: Make GetCurrentLocale return a std::string instead of a reference to a static buffer.
For win32 this is even a fix, because the static buffer was only updated once. Later calls discarded the determined locale.
2025-05-06 18:29:41 +02:00
frosch 0d5b3ebd7f Codechange: Declare all IntervalTimers const, which can be const. 2025-05-06 18:29:41 +02:00
frosch 61cec33be2 Codechange: Add 'const' to static variables, which are only initialised once. 2025-05-06 18:29:41 +02:00
frosch 1900125c98 Codechange: Use string_view for FileExists. 2025-05-06 18:29:41 +02:00
Peter Nelson d571491405
Codechange: Replace `std::bitset<CONTENT_TYPE_END>` with `ContentTypes`. (#14223)
#14214 added `ContentTypes` as en `EnumBitSet`, but some std::bitset existed already; they are now `ContentTypes` too.
2025-05-06 17:20:01 +01:00
translators eca826b0a4 Update: Translations from eints
korean: 7 changes by telk5093
hungarian: 3 changes by vargaviktor
latvian: 3 changes by lexuslatvia
polish: 6 changes by pAter-exe
2025-05-06 04:46:37 +00:00
frosch 13349254ea
Fix #14216, d030d17: RealSpriteGroups referencing CallbackResultSpriteGroups were always treated as callback-failure. (#14218) 2025-05-05 16:13:41 +02:00
Peter Nelson e23de03a99 Codechange: Use FlatSet for sprite picker list. 2025-05-05 14:00:38 +01:00
Peter Nelson b06273f716 Codechange: Use FlatSet when searching tiles around stations. 2025-05-05 14:00:38 +01:00
Peter Nelson 7679b0bc46 Codechange: Use FlatSet when filtering and drawing badge names. 2025-05-05 14:00:38 +01:00
Peter Nelson 5fd7344a6d Codechange: Use FlatSet when creating rivers. 2025-05-05 14:00:38 +01:00
Peter Nelson 7c834921b2 Codechange: Use FlatSet for per-industry type industry lists. 2025-05-05 14:00:38 +01:00
Peter Nelson 6070f8d4f3 Codechange: Add FlatSet implementation.
This is a flat set implemented using a sorted vector for storage.
2025-05-05 14:00:38 +01:00
Peter Nelson 2355d67e11
Codechange: Use EnumBitSet instead of Vector to record received content types. (#14214) 2025-05-05 08:55:34 +01:00
translators a46b885640 Update: Translations from eints
english (au): 1 change by krysclarke
russian: 2 changes by Ln-Wolf
2025-05-05 04:47:18 +00:00
Peter Nelson d7563096c6
Doc: Tweak documentation for consistency. (#14211)
* Remove/add line breaks so spacing is the same.
* Fix ToC links.
2025-05-04 20:16:29 +01:00
Peter Nelson ac76212b80 Fix: Closing the Game Options window closes all textfile windows.
Record the parent window that opens a textfile window so only child windows are closed instead of all.
2025-05-04 19:36:46 +01:00
Peter Nelson dabf2ede67 Change: Add methods to close child windows with a specific window number. 2025-05-04 19:36:46 +01:00
Rubidium 0724b3cda8 Codechange: replace SQChar with char 2025-05-04 16:59:06 +02:00
Rubidium 1f411f8a16 Codechange: use string_view for squirrel parameter checks 2025-05-04 16:59:06 +02:00
Rubidium 588b0de3de Codechange: hide SQString internals behind std::string_view/std::span 2025-05-04 16:59:06 +02:00
Rubidium 635ca3739f Codechange: use std::string_view in squirrel lexer 2025-05-04 16:59:06 +02:00
Rubidium 4255a94779 Codechange: use std::span over char* for writing the buffers 2025-05-04 15:32:52 +02:00
Rubidium 6817f52d9b Codechange: move definition of getcwd for Windows to where it is used 2025-05-04 15:32:52 +02:00
Rubidium 6189bbc45a Codechange: return std::string_view for convert_from_fs 2025-05-04 15:32:52 +02:00
Rubidium 6caa08098c Codechange: remove char* StringConsumer 2025-05-04 15:32:52 +02:00
Peter Nelson 3e608b5fe4
Fix: Zoom-scroll extra viewports only if the mouse cursor is over the viewport. (#14209) 2025-05-04 14:16:05 +01:00
Rubidium afc1e76575 Codefix: StartNewThread uses char* after returning 2025-05-04 14:05:15 +02:00
Rubidium 8f74c08ea6 Codechange: put SQRegFunctions into initializer_list and use ranged for loops 2025-05-04 14:05:05 +02:00
Rubidium f4fc8f6b38 Codechange: replace Error with simple throw 2025-05-04 14:05:05 +02:00
Rubidium 9d8a612bfb Codechange: remove unused function 2025-05-04 10:43:56 +02:00
Rubidium 5e3c7c4146 Codechange: `char*` -> `char *` 2025-05-04 10:43:56 +02:00
Rubidium 3f2b39e3f8 Codechange: replace char* where out-of-date 2025-05-04 10:43:56 +02:00
Rubidium d697280493 Codechange: remove now obsolete char* tests
The function is std::string_view and there are std::string_view tests as well.
2025-05-04 10:43:56 +02:00
Rubidium d01bebbd18 Codefix 26a4da9b01: MinGW compilation failure 2025-05-04 09:07:02 +02:00
translators 7d7a6bd32c Update: Translations from eints
norwegian (bokmal): 3 changes by eriksorngard
2025-05-04 04:46:05 +00:00
frosch 8571af9833 Codechange: Turn ZoomLevel into enum class. 2025-05-03 23:21:09 +02:00
frosch c0d4ab69d0 Codechange: Add a container to index data by zoom level. 2025-05-03 23:21:09 +02:00
frosch 7055ea0aee Codechange: Define sequential operators for ZoomLevel. 2025-05-03 23:21:09 +02:00
frosch bbfda39ac3 Codechange: Add ZoomLevels bit set. 2025-05-03 23:21:09 +02:00
frosch 48d09af039 Codechange: Simplify weird range check. 2025-05-03 23:21:09 +02:00
Rubidium d464961c41 Codechange: use std::string_view for SQ stack and function info 2025-05-03 23:02:09 +02:00
Rubidium 0bc773215e Codechange: use std::optional<std::string_view> to make the intent of function clearer 2025-05-03 23:02:09 +02:00
Rubidium ead3b96883 Codechange: use std::string_view to create SQString 2025-05-03 23:02:09 +02:00
Rubidium fca99967a7 Codechange: make sq_scratchpad use std::span<char> 2025-05-03 23:02:09 +02:00
Rubidium b4d9682f21 Codechange: use std::string_view for sq_throwerror 2025-05-03 23:02:09 +02:00
Rubidium ec79ceb2be Codechange: use std::string_view for sq_pushstring 2025-05-03 23:02:09 +02:00
Rubidium 3020e615a9 Codechange: use std::string_view for squirrel compilation 2025-05-03 23:02:09 +02:00
Rubidium 26a4da9b01 Codechange: replace last strncmp uses 2025-05-03 21:51:01 +02:00
Peter Nelson 31754a0afd
Fix: Changing monospace font didn't refresh the monospace width cache. (#14185) 2025-05-03 18:34:45 +01:00
Peter Nelson 7596f98e2d
Codechange: Cache layouted text for the last used width. (#14177) 2025-05-03 18:33:47 +01:00
Peter Nelson bd1a3fe0b7
Change: Remove the limit of 20 parameters to a Script Text string. (#14193) 2025-05-03 18:33:29 +01:00
frosch 518a34c286 Codechange: Use std::byte for generic buffers. 2025-05-03 18:43:20 +02:00
frosch 02082a0211 Codechange: Deduplicate array lookup. 2025-05-03 18:43:20 +02:00
frosch bb767608de Codechange: Pass SpriteType as direct parameter to SpriteEncoder::Encoder. 2025-05-03 18:43:20 +02:00
frosch c3aa3f140c
Codechange: Use more std::string_view. (#14197) 2025-05-03 18:40:37 +02:00
frosch 74a275f37b
Add: [NewGRF] Add purchase list Action3 CID for houses, industries, industry tiles, airports and airport tiles. (#14121) 2025-05-03 17:50:20 +02:00
frosch 9ac9798d7f
Codechange: Remove usages of stoi and stol. (#14196) 2025-05-03 17:46:30 +02:00
Rubidium b6afd8d2b6 Codechange: remove some completely unused squirrel files 2025-05-03 17:14:10 +02:00
Rubidium 85f1110569 Codechange: rewrite ini file parsing with the StringConsumer 2025-05-03 17:13:33 +02:00
Rubidium 6a9f694158 Codechange: remove StrEmpty 2025-05-03 15:58:14 +02:00
Rubidium d037dbb42a Codechange: use std::string_view for locales 2025-05-03 15:58:14 +02:00
Rubidium 96fd291693 Codechange: introduce GetEnv that returns optional based on std::getenv 2025-05-03 15:58:14 +02:00
Rubidium 04a6a55e94 Codechange: replace StripTrailingWhitespace with StrTrimView 2025-05-03 15:57:53 +02:00
Rubidium 1f39d469ff Codechange: pass the characters to trim to StrTrimView 2025-05-03 15:57:53 +02:00
Rubidium e2db8277b8 Codefix: implement StrTrimInPlace without assigning a borrowed view of itself 2025-05-03 15:57:53 +02:00
Rubidium 4109b6848b Codechange: replace manual trim and std::from_chars with ParseInteger 2025-05-03 15:57:53 +02:00
Rubidium 414f6a3067 Codechange: add support for parsing octal numbers 2025-05-03 15:57:53 +02:00
Rubidium c79abc6da6 Codechange: reduce dependence on C-style strings in OpenGL 2025-05-03 14:24:49 +02:00
Rubidium 278aee2c19 Codechange: use std::string_view for sq_getstring 2025-05-03 14:24:28 +02:00
translators f4f05dea33 Update: Translations from eints
chinese (traditional): 1 change by KogentaSan
chinese (simplified): 1 change by WenSimEHRP
greek: 1 change by gh658804
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
dutch: 8 changes by Afoklala
portuguese: 3 changes by jcteotonio
portuguese (brazilian): 1 change by pasantoro
polish: 1 change by pAter-exe
2025-05-03 04:45:31 +00:00
Peter Nelson 8b14faaa40
Codechange: Add version of DrawStringMultiLine that performs clipping test. (#14189)
Normally DrawStringMultiLine does not perform any clipping, as the return value may be needed if it the text is not drawn.

In some specific cases the height is already known, so it is possible to test for clipping, which can cut down on layouting time for text which won't be visible.
2025-05-02 22:59:55 +01:00
Iris-Persephone 2f020abe74
Add: "Many random towns" button in scenario editor now prompts for the number of towns, with defaults based on new game settings (#14158) 2025-05-02 22:54:21 +01:00
Peter Nelson 3eba97f67c
Codechange: Scrollbar Count no longer needs to be clamped to uint16_t. (#14184) 2025-05-02 22:21:05 +01:00
Peter Nelson f7db4938ce
Fix #14098: Use 64-bit type for MIDI realtime information. (#14144) 2025-05-02 22:20:44 +01:00
Rubidium c420ba349d Codechange: use std::string_view over char* 2025-05-02 23:12:43 +02:00
Rubidium f2a32c6d13 Codechange: use std::byte instead of char for calculating arbitrary byte offsets 2025-05-02 23:12:43 +02:00
Peter Nelson 932dca927b
Fix: Crash/Undefined behaviour in station view window. (#14183)
No column limit was applied when drawing waiting cargo, which could cause out-of-bounds array access.
2025-05-02 08:02:35 +01:00
translators e0a9c7d818 Update: Translations from eints
english (au): 2 changes by krysclarke
chinese (traditional): 3 changes by KogentaSan
chinese (simplified): 6 changes by WenSimEHRP
greek: 2 changes by gh658804
russian: 2 changes by Ln-Wolf
finnish: 3 changes by hpiirai
portuguese (brazilian): 2 changes by pasantoro
polish: 2 changes by pAter-exe
2025-05-02 04:45:34 +00:00
Peter Nelson ae9646eb0a
Change: Use same padding as NewGRF parameters for AI/GS parameters lists. (#14118) 2025-05-01 22:36:53 +01:00
Rubidium 5ca686261e Codechange: use std::string_view for the string setting defaults 2025-05-01 23:24:43 +02:00
Rubidium 5c7b04a0c2 Codechange: use std::string_view for 'x-of-many' settings 2025-05-01 23:24:43 +02:00
Rubidium 7805c1c189 Codechange: use std::string_view for ini_key 2025-05-01 23:24:43 +02:00
Peter Nelson d958d50985
Fix: Small order list arrow was wrong direction for RTL text. (#14174)
Add sprite for small left arrow and use for small order list when using an RTL language.
2025-05-01 22:08:24 +01:00
Loïc Guilloux 41b113840a
Fix: [Script] Access to enum/consts defined outside of main.nut (#14176) 2025-05-01 18:16:32 +02:00
Loïc Guilloux 1f212e6f2a
Fix: Handle \t when loading GS strings from savegame (#14180) 2025-05-01 16:48:02 +02:00
Loïc Guilloux 6f4994329c
Fix bf8a241f: Handle \t in trailing whitespaces (#14178) 2025-05-01 12:32:00 +02:00
translators a30f251d05 Update: Translations from eints
hungarian: 99 changes by meskobalazs
russian: 8 changes by Ln-Wolf
finnish: 24 changes by hpiirai
latvian: 70 changes by lexuslatvia
2025-05-01 04:47:22 +00:00
Rubidium fbe80f31fe Codechange: replace char* in GetOptData with std::string_view 2025-04-30 23:49:06 +02:00
Rubidium c1a287ad17 Codechange: make some saveload functions work natively with std::string_view 2025-04-30 23:49:06 +02:00
Rubidium 855377191e Codechange: replace some more char*s with std::string_view 2025-04-30 23:49:06 +02:00
frosch a80c11a6e8
Fix 66733e2a: Textbuf was broken, and did not insert any input. (#14173) 2025-04-30 19:31:52 +00:00
Peter Nelson 7dd3bed10f
Fix #14170, 7fd0e6c27d: Missing spaces for timetabled order strings. (#14172) 2025-04-30 19:54:54 +01:00
frosch 316279f4b4 Codechange: Use more std::string_view. 2025-04-30 19:33:56 +02:00
frosch 9cf36dac39 Codechange: Use data() instead of c_str(), if no NUL termination is needed. 2025-04-30 19:33:56 +02:00
frosch 9e90d4ed79 Codefix: Do not assign nullptr to std::string_view. 2025-04-30 19:33:56 +02:00
frosch 36ce1f890a Codechange: Remove c_str, if std::string_view is already accepted. 2025-04-30 19:33:56 +02:00
frosch b564fbb5e6 Codechange: Use StringConsumer to parse hotkeys. 2025-04-30 19:33:56 +02:00
frosch 66733e2a50 Codechange: Use std::string_view in IME input handling. 2025-04-30 19:33:56 +02:00
frosch 6db13df3b5 Add: [BaseSet] Allow basesets to set minor and patch versions in obg/obs/obm files. 2025-04-30 15:23:27 +02:00
frosch d30fee4a99 Codechange: Improve debug/error messages when reading baseset metadata. 2025-04-30 15:23:27 +02:00
Rubidium 708e6a512d Codechange: replace char* with C++ style strings 2025-04-30 12:05:04 +02:00
Peter Nelson 356b0159c7
Fix 261e09a549: Compilation failure with Fluidsynth enabled. (#14167) 2025-04-30 07:27:57 +01:00
translators 7bec2029fa Update: Translations from eints
english (au): 4 changes by krysclarke
norwegian (bokmal): 5 changes by eriksorngard
chinese (traditional): 4 changes by KogentaSan
greek: 8 changes by gh658804
russian: 4 changes by Ln-Wolf
finnish: 4 changes by hpiirai
portuguese: 4 changes by jcteotonio
portuguese (brazilian): 4 changes by pasantoro
polish: 4 changes by pAter-exe
2025-04-30 04:46:51 +00:00
Peter Nelson 0abebfce1c
Codechange: Use result of .find() instead of looking up multiple times. (#14154) 2025-04-29 23:52:46 +01:00
Peter Nelson aa9e8b422c
Fix #14166, dfd9fbf873: Loan was no longer invalidated when refreshing finance window. (#14168)
In most cases the company loan does not change, but it should be updated in case it does.
2025-04-29 23:52:11 +01:00
Rubidium f4ad614285 Codechange: use std::string_view for FS2OTTD and OTTD2FS 2025-04-29 22:33:32 +02:00
Rubidium ef71ce0a9d Codechange: return std::string_view for Textbuf::GetText() 2025-04-29 22:15:49 +02:00
Rubidium 261e09a549 Codechange: remove char* from base driver code 2025-04-29 21:09:18 +02:00
frosch d030d17bd6 Codechange: Do not use a mutable global to return calculated VarAction2 results. 2025-04-29 20:35:46 +02:00
frosch e90b68d504 Codechange: Pass SpriteGroup as reference to ResolveReal. 2025-04-29 20:35:46 +02:00
frosch 7c946d97da Codefix: Build with OPTION_DEDICATED=OFF and CMAKE_DISABLE_PRECOMPILE_HEADERS=ON. 2025-04-29 20:26:23 +02:00
frosch afe3dfb3a4 Codechange: Use format instead of to_string. 2025-04-29 20:26:23 +02:00
frosch fda93b6f35 Codechange: Add format_append as short-hand to format_to + back_inserter. 2025-04-29 20:26:23 +02:00
frosch 98481ecc01 Codechange: Replace strtol, strtoll, stroul and strtoull with ParseInteger. 2025-04-29 20:14:56 +02:00
frosch cdafc50c94 Codechange: Replace atoi and atoll with ParseInteger. 2025-04-29 20:14:56 +02:00
frosch 3973199879 Change: ParseInteger now checks for trailing junk chars. 2025-04-29 20:14:56 +02:00
frosch 79b2202f2e Codechange: Use StringConsumer for parsing more strings. 2025-04-29 20:14:56 +02:00
frosch e7d758c82a Codechange: Replace sscanf with StringConsumer. 2025-04-29 20:14:56 +02:00
frosch 8027e31f47 Codechange: Remove virtual functions SpriteGroup::GetResult and GetNumResults. They are only implemented in and called via ResultSpriteGroup. 2025-04-29 10:35:10 +02:00
frosch 010b944173 Codechange: Move SpriteGroup cast from callers into Resolve. 2025-04-29 10:35:10 +02:00
Rubidium af25eecc15 Codechange: use const for std::string_view where appropriate 2025-04-29 10:15:18 +02:00
Rubidium 78250c3bba Codechange: remove const char* overloads when there are std::string_view and std::string& overloads 2025-04-29 10:14:53 +02:00
Peter Nelson a5578166bb Codechange: Pass Script Info by reference. 2025-04-28 23:08:20 +01:00
Peter Nelson 341cdbc16b Codechange: Pass Script engine by reference. 2025-04-28 23:08:20 +01:00
Peter Nelson 72ca962b84 Codechange: Pass ScriptInstance by reference. 2025-04-28 23:08:20 +01:00
Peter Nelson 13fcc0900e
Change: Use enum/bitset to track which script configuration items are defined. (#14150)
Removes magic numbers, and simplifies compatibility. It is no longer necessary to provide values which won't be used.
2025-04-28 23:07:57 +01:00
Rubidium b20b56d5fc Codechange: store revision information in C++ style strings 2025-04-28 23:48:32 +02:00
Rubidium 8b1c1cc33d Codechange: provide 'sv' (string_view) literals globally 2025-04-28 23:39:33 +02:00
Rubidium be53bd320d Codechange: replace char* from settingsgen 2025-04-28 23:27:46 +02:00
frosch 47b5ca6115 Fix: [NewGRF] Computed VarAction2 callback results were not always properly masked to 15 bit results. 2025-04-28 23:25:31 +02:00
frosch d90f6f01cc Codechange: CALLBACK_FAILED is an internal constant, do not use it as numeric value in VA2 computations. 2025-04-28 23:25:31 +02:00
frosch 30b1eb6e5f
Fix: [NewGRF] The result of Action123 evaluation affected rerandomisation in a weird corner case. (#14139)
Rerandomisation does not care about the Resolve result.
But we skipped it, in case of 'invalid SpriteGroup reference'.
2025-04-28 23:24:42 +02:00
frosch b281c5616e Change: [NewGRF] If Action123 does not resolve in a valid SpriteSet, prefer drawing the default sprite instead of an invalid sprite. 2025-04-28 22:20:54 +02:00
frosch 7b08170ac8 Codechange: Replace a magic value with a maybe less magical constant. 2025-04-28 22:20:54 +02:00
Rubidium 360670626b Codechange: replace char* with std::string_view 2025-04-28 21:31:12 +02:00
Rubidium 9107c3f6c6 Codechange: add std::string_view variant of FileHandle::Open 2025-04-28 21:31:12 +02:00
Peter Nelson 2c4897c2cd
Codechange: Use EnumBitSet for HouseZones. (#14137) 2025-04-28 20:27:43 +01:00
frosch f5a9eae8b1 Fix: [NewGRF] AI station construction callback did not work for stations with ID >= 0x100. 2025-04-28 20:50:13 +02:00
frosch e2084bbdcd Codechange: Replace out parameters with result tuples. 2025-04-28 20:50:13 +02:00
frosch 0c6426cb2d Fix: Out-of-bounds read, if NewGRF stations provided no spritesets. 2025-04-28 20:49:20 +02:00
frosch 0f1ef96ca1 Codechange: Road stops do not use RealSpriteGroup, ResolveReal is never called. 2025-04-28 20:49:20 +02:00
Rubidium 9116f96e2e Codechange: replace char * with std::string_view 2025-04-28 17:53:18 +02:00
Rubidium c6ea0ce961 Codechange: use std::span for transferring data in network code 2025-04-28 17:53:18 +02:00
frosch b7e7f08f78 Codechange: Simplify usage of GRFFileProps by adding some common helper methods. 2025-04-28 13:44:46 +02:00
frosch 46494c6d44 Codechange: Rename GRFFileProps to SubstituteGRFFileProps. 2025-04-28 13:44:46 +02:00
Richard Wheeler 298e02d593
Fix: List Ctrl+Click behaviour for vehicle details tooltip (#14127)
Also change mention of "road vehicle" to "vehicle", in line with vehicle order, refit, reverse, etc. tooltips. Fixes #14128
2025-04-28 07:00:18 +01:00
translators 68ba2735ea Update: Translations from eints
swedish: 109 changes by Brickblock1
spanish (mexican): 1 change by absay
english (us): 1 change by 2TallTyler
2025-04-28 04:46:30 +00:00
Rubidium 794ba1f5da Fix 29ceaf0a8: checking std::optional against nullptr caused crash 2025-04-27 21:10:12 +02:00
Rubidium 49ef3eee13 Codechange: replace char* with std::string_view 2025-04-27 20:08:02 +02:00
frosch e1859df1c0 Codechange: Use enums as keys for the spritegroups in FixedGRFFileProps. 2025-04-27 19:50:51 +02:00
frosch 05504ec463 Codechange: Use SingleGRFFileProps, if the feature has no spritegroup keys. 2025-04-27 19:50:51 +02:00
frosch 41a20e512d Codechange: Use proper enum type to index sprite groups in VariableGRFFileProps. 2025-04-27 19:50:51 +02:00
frosch 893aa0fb91 Codechange: Add an explicit enum member for the default spritegroup of badges. 2025-04-27 19:50:51 +02:00
Rubidium 29ceaf0a84 Codechange: use std::string_view over const char * 2025-04-27 18:04:04 +02:00
Rubidium c7056866a3 Codechange: remove manual param count; in all cases strlen(params) == nparams 2025-04-27 17:57:53 +02:00
Rubidium 781187b8a6 Codechange: replace C-style strings with std::string_view related to strings functions 2025-04-27 17:57:42 +02:00
Rubidium 4e3e3d5be6 Codechange: introduce transparent hash lookup for strings 2025-04-27 17:57:42 +02:00
Peter Nelson 7bbf380931
Fix #14125, 828e808444: NewGRF sounds were not loaded. (#14130)
NewGRF Action 11 should be handled in both INIT and ACTIVATION stages for sounds to be loaded.

Additionally the Action 0 feature test failed due to offsets involved.
2025-04-27 15:20:38 +00:00
Rubidium b9667ec3d1 Codechange: use std::string_view for scripts 2025-04-27 17:00:25 +02:00
translators 864fe29028 Update: Translations from eints
english (au): 1 change by krysclarke
chinese (traditional): 1 change by KogentaSan
galician: 66 changes by pvillaverde
chinese (simplified): 1 change by WenSimEHRP
korean: 72 changes by telk5093
greek: 1 change by gh658804
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
portuguese: 1 change by jcteotonio
portuguese (brazilian): 1 change by pasantoro
polish: 1 change by pAter-exe
2025-04-27 04:44:13 +00:00
Peter Nelson 5a7893b730
Fix #14104, 67a0fcc: Don't base timetable timing decisions on client settings. (#14105)
Client settings different between clients so the resultant timings may be different.

Partially reverts 67a0fcc.
2025-04-26 22:39:01 +01:00
Peter Nelson b87ce9c845
Change: Draw info headers as shade of window colour instead of pixel colour. (#14123)
Use the normal or lightest colour gradient to pick a suitable colour, instead of an arbitrary pixel colour.

(Except for the NewGRF window's info panel, this happens to be the same colour.)
2025-04-26 22:38:24 +01:00
frosch 55fad9c78a
Add: Limit height of settings description, and add scrollbar. (#14102) 2025-04-26 22:34:18 +02:00
frosch d85f6dccc5
Fix 5575379: Crash with default airports. (#14120) 2025-04-26 22:29:01 +02:00
frosch f62f728187
Codechange: Move usage of ResolverObjects to newgrf_xxx.cpp (#14116) 2025-04-26 20:53:50 +02:00
frosch be39a05327 Fix: Road vehicle blocking and train collissions used slightly inconsistent distance thresholds. 2025-04-26 19:32:59 +02:00
frosch 3a70d1e2f7 Codechange: Pass the max-distance as parameter to VehiclesNearTileXY. 2025-04-26 19:32:59 +02:00
frosch 2df1233f1f Codechange: Clamp the search area to valid values for the hash bucket selection.
The bucket selection uses a truncating division instead of a flooring division, so it does not work for negative positions.
Anyhow, there are no negative tile coordinates, so just clamp the search area.
2025-04-26 19:32:59 +02:00
frosch 0f76ba122c Codefix: VehiclesNearTileXY yielded all vehicles with matching hashes, even if they are far away. 2025-04-26 19:32:59 +02:00
frosch c14e4a6db1 Codefix: Rect::Contains did not consider the bottom/right edges as inside. 2025-04-26 19:32:59 +02:00
Rubidium 3235ec4cf8 Codefix: checking unsigned int >= 0 is pointless, check before subtraction 2025-04-26 18:31:36 +02:00
frosch ce2155ab27 Codechange: Remove unused FindVehicleOnPosXY/HasVehicleOnPosXY. 2025-04-26 16:54:56 +02:00
frosch 98ac75e74f Codechange: Replace FindVehicleOnPosXY/HasVehicleOnPosXY with VehiclesNearTileXY/HasVehicleNearTileXY. 2025-04-26 16:54:56 +02:00
frosch 9f1c04c0e1 Codechange: Add VehiclesNearTileXY and HasVehicleNearTileXY to iterate over/check for ground vehicles near a tile coordinate. 2025-04-26 16:54:56 +02:00
frosch ac3ed9f3ad Codechange: Deduplicate and simplify tile hash arithmetic. 2025-04-26 16:54:56 +02:00
Rubidium b4d4d730a5 Codechange: use std::string_view for town name generation 2025-04-26 16:30:30 +02:00
Rubidium 30f381acee Codechange: use std::string_view for NetworkAddress 2025-04-26 16:30:16 +02:00
Rubidium e1db09a41f Codechange: use std::string_view for NewsTypeData 2025-04-26 16:30:16 +02:00
Rubidium 42f0aa24f6 Codechange: use std::string_view for connection/URI strings 2025-04-26 16:30:16 +02:00
Rubidium a5812a45f8 Codechange: use std::string view for URI and std::move for data 2025-04-26 16:30:16 +02:00
Rubidium d1a7d30572 Codechange: use std::string_view for some settings functions 2025-04-26 16:30:16 +02:00
Rubidium 4476ce804d Codechange: use std::string_view for GetNextParameterString 2025-04-26 16:30:16 +02:00
frosch 398524e49a
Add: [NewGRF] Provide random bits in var10 of house callback 1C 'construction stage changed'. (#14095) 2025-04-26 15:58:44 +02:00
frosch 55753795bf
Fix: [NewGRF] Cargo-types for airport-tile animation-triggers were not properly translated. (#14092) 2025-04-26 15:58:30 +02:00
frosch 1ea1dbd19e
Add: [NewGRF] Station/roadstop animation-triggers 'tile loop' (bit 7) and 'path reservation' (bit 8). (#14080) 2025-04-26 14:44:55 +02:00
frosch d3ae6bc9a8
Fix: [NewGRF] For animation-triggers which do not supply a cargo-type in var18, the var18 bits should remain empty. (#14091) 2025-04-26 14:44:07 +02:00
frosch 0d9074769d
Change: [NewGRF] Animation-trigger 'construction stage changed' of houses and industries now also triggers at construction start. (#14089) 2025-04-26 14:42:49 +02:00
Rubidium 365eed533d Codechange: use std::string_view for console commands 2025-04-26 14:15:10 +02:00
Rubidium f04cf54939 Codechange: make IConsoleCmdExec use C++ strings internally 2025-04-26 14:15:10 +02:00
Loïc Guilloux 28d0e6dfc0
Change: [Script] Reject scripts using negative version (#14096) 2025-04-26 14:02:36 +02:00
Peter Nelson 4a5db57f7b
Fix #14107: Mark the company value in the company view window dirty when it changes. (#14112) 2025-04-26 11:56:11 +00:00
Peter Nelson dfd9fbf873
Codechange: Defer refreshing company finance windows. (#14111)
During each game tick every cargo payment will issue an Invalidate of the status bar and company finance window. While this doesn't paint the window yet, it does need to search for open windows, and then mark a area of dirty blocks, which is done for every Invalidate.

Instead, set a bit in a CompanyMask, and test these bits once after the game tick is complete.

This reduces the amount of dirtying, and allows more specific widgets to be dirtied instead of the whole window.
2025-04-26 10:50:51 +00:00
Peter Nelson a1f086e60c
Fix #14107: Invalidate all shared vehicle windows when changing group. (#14110)
Previously only windows of the first vehicle were invalidated.
2025-04-26 10:49:41 +00:00
translators bb1d561369 Update: Translations from eints
chinese (traditional): 9 changes by KogentaSan
english (us): 66 changes by 2TallTyler
greek: 65 changes by gh658804
russian: 77 changes by Ln-Wolf
dutch: 66 changes by Afoklala
portuguese: 65 changes by jcteotonio
polish: 68 changes by pAter-exe
2025-04-26 04:44:12 +00:00
Rubidium 08ce16018b Codechange: make start-ai console command parsing work with std::string_view 2025-04-25 19:04:22 +02:00
Rubidium ccbf7f4a46 Codechange: validate the given seed 2025-04-25 19:04:22 +02:00
Rubidium 86039a5b69 Codechange: make SetDebugString use C++-style strings and function types 2025-04-25 19:04:22 +02:00
Rubidium 498a0f1c1b Codechange: use C++ strings over C-strings 2025-04-25 19:04:22 +02:00
frosch 4a09860c53
Fix: Focus settings filter box (only) when the tab becomes active. (#14100) 2025-04-25 12:04:26 +02:00
frosch f554d799d7
Change: [NewGRF] Provide shared random bits in multi-tile animation-triggers of airport tiles and objects, just like for other features. (#14090) 2025-04-25 10:01:01 +02:00
Peter Nelson 8b927220c7
Change: Move Game Options toggles to before label, add Off/On text. (#14097) 2025-04-25 07:49:33 +01:00
translators e61762a805 Update: Translations from eints
english (au): 65 changes by krysclarke
norwegian (bokmal): 67 changes by eriksorngard
chinese (traditional): 67 changes by KogentaSan
spanish (mexican): 66 changes by absay
chinese (simplified): 91 changes by WenSimEHRP
finnish: 65 changes by hpiirai
french: 61 changes by ottdfevr
portuguese (brazilian): 65 changes by pasantoro
2025-04-25 04:46:37 +00:00
Peter Nelson 87b5b0ffa3
Fix 2b80812922: Map size column in server list may be too wide. (#14094)
Incorrect change from SetDParamMaxValue to GetParamMaxValue.
2025-04-24 21:05:31 +01:00
Rubidium 2087bca87d Codechange: replace atoi with ParseInteger in console commands 2025-04-24 18:10:01 +02:00
Rubidium ddc0d6ead3 Codechange: use string comparision for ConExec's second parameter 2025-04-24 18:10:01 +02:00
Richard Wheeler a01d47b333
Doc: Correct baseset obg file MD5 and url documentation (#14086) 2025-04-24 12:24:32 +01:00
frosch 880a947eb3 Fix: [NewGRF] Randomisation-trigger 'path reservation' did not work for waypoints. 2025-04-24 09:19:43 +02:00
frosch bc0eaf9ac4 Codechange: Allow passing waypoints to Trigger(Station|RoadStop)Randomisation. 2025-04-24 09:19:43 +02:00
Peter Nelson c0cd7cafe4
Change: Remove minimum width from advanced settings panel of Game Options window. (#14088)
Previous minimum width of 400 was fairly arbitrary and isn't necessary when
the minimum size is suitably constrained by other widgets in the window.

This allows the window to be narrower for CJK languages.
2025-04-23 23:39:35 +00:00
Peter Nelson 7846f0f4ee
Fix a4dc7249ee: Changing language or interface scale could hang. (#14087)
A bit of hysteresis caused by OnResize calling ReInit calling OnResize calling ReInit calling OnResize calling ReInit ...
2025-04-24 00:29:54 +01:00
Peter Nelson 78d3eaf3e2 Change: Slider widget can now be colourful. 2025-04-23 19:07:52 +01:00
Peter Nelson 20738865f0 Change: Use standard mauve/yellow scheme for game options window.
This is the colour scheme used by AI/GS settings, NewGRF settings and (previously) advanced settings.
2025-04-23 19:07:52 +01:00
Peter Nelson 17e7dafa2a Change: Add alternate_colour widget data for boolean button.
Allows boolean button to have different background and button colours.
2025-04-23 19:07:52 +01:00
Peter Nelson 7953a97cbb Change: Adjust section names in Graphics options tab.
"Interface size" and "Graphics" section names do not make much sense any more.
2025-04-23 19:07:52 +01:00
Peter Nelson 77da79a052 Codechange: Remove unnecessary SetMinimalSize from Game Options window. 2025-04-23 19:07:52 +01:00
Peter Nelson a4dc7249ee Change: Merge Game Options and Game Settings together.
Game Settings is now an additional 'Advanced' tab in the Game Options window.
2025-04-23 19:07:52 +01:00
frosch 6f056283f2
Fix: [NewGRF] For roadstop multi-tile-animation-triggers, the upper 16 bits were not the same for all tiles. (#14084) 2025-04-23 19:26:09 +02:00
Loïc Guilloux f8bdc1e612
Fix f5ffd47: Don't skip separator while reading a record (#14083) 2025-04-23 17:30:51 +02:00
Peter Nelson 6d5aee0545
Codechange: Restructure RoadStop Entries to reduce pointers. (#14069)
A RoadStop must own both west and east `Entry`s, but they are allocated separately.

Combine this allocation into one instead.
2025-04-23 08:29:34 +01:00
Peter Nelson 41ed5f9822
Fix c7d6934816: Town view caption lost "(City)" flag. (#14082) 2025-04-23 08:14:08 +01:00
translators d9dc6cb5e4 Update: Translations from eints
english (au): 1 change by krysclarke
chinese (traditional): 7 changes by KogentaSan
chinese (simplified): 201 changes by WenSimEHRP
greek: 1 change by gh658804
hungarian: 9 changes by meskobalazs
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
latvian: 1 change by lexuslatvia
portuguese: 1 change by azulcosta
portuguese (brazilian): 1 change by pasantoro
polish: 1 change by pAter-exe
2025-04-23 04:46:38 +00:00
Peter Nelson d028c7f9e2
Codefix: Incorrect type for OnDropdownSelect widget parameter. (#14074) 2025-04-22 22:44:25 +01:00
Rubidium 4149384ebc Codechange: simplify and move GetArgumentInteger 2025-04-22 23:16:15 +02:00
frosch 2bee313642 Codechange: Replace FindVehicleOnPos with 'for' loop. 2025-04-22 22:12:59 +02:00
frosch 06c399b79e Codechange: Replace HasVehicleOnPos and callbacks with HasVehicleOnTile and lambda-predicates. 2025-04-22 22:12:59 +02:00
frosch dacd77b2bd Codechange: Use FindVehicleOnPos instead of HasVehicleOnPos, if there is no stop condition. 2025-04-22 22:12:59 +02:00
frosch fca3103d8c Codechange: Add iterator for vehicles on a tile. 2025-04-22 22:12:59 +02:00
Rubidium 917ef03e97 Codechange: use std::string_view in IConsole settings API 2025-04-22 19:52:37 +02:00
Rubidium b279bc37e7 Codechange: use std::string_view to set string settings 2025-04-22 19:52:37 +02:00
Rubidium fdb8defa64 Codechange: use std::string_view to parse setting values 2025-04-22 19:52:37 +02:00
Peter Nelson 12118b201c
Change: Enhance visibility of disabled bool button. (#14071)
Apply masked fill to background as well.
2025-04-22 17:37:30 +01:00
translators 415ac07a08 Update: Translations from eints
chinese (simplified): 32 changes by WenSimEHRP
hungarian: 38 changes by meskobalazs
2025-04-22 04:46:01 +00:00
Peter Nelson 3aa82d5e63
Codechange: Use EnumBitSet for RoadStopStatusFlags. (#14068) 2025-04-21 20:16:23 +01:00
Peter Nelson 81edd1123a
Change: Use scaled instead of fixed dimensions for framerate graphs. (#14039) 2025-04-21 20:15:57 +01:00
frosch d7ddea4032
Codechange: Turn AnimationTrigger enums into enum classes. (#14067) 2025-04-21 20:53:31 +02:00
frosch 61a0a520f6
Codechange: Unify random trigger enums and turn them into enum classes. (#14066) 2025-04-21 20:03:34 +02:00
frosch f399b8eb29 Codechange: Unify naming of NewGRF animation callbacks. 2025-04-21 19:06:13 +02:00
frosch 264abfafe6 Codechange: Rename storage of random triggers to include the term 'random'. 2025-04-21 19:06:13 +02:00
frosch 39220a5feb Codechange: Unify naming of NewGRF random trigger functions. 2025-04-21 19:06:13 +02:00
frosch 368d131fb7 Codechange: Use 'construction stage' consistently, instead of 'construction state'. 2025-04-21 19:06:13 +02:00
frosch 98445088b1
Codechange: Move VehicleEnteredDepotThisTick call to a more suitable position. (#14065) 2025-04-21 17:52:03 +02:00
Peter Nelson 7d03cee512
Change: Include dragged train in depot tile length display. (#14060)
In the depot, when dragging a train over another train, the tile length displayed now includes the length of the dragged train.

As the parts are not moved yet, length changes due to callbacks are not taken into account.
2025-04-21 16:37:10 +01:00
frosch 2a62eea005
Codefix: Comment style. (#14064) 2025-04-21 17:25:09 +02:00
Peter Nelson 5b2754fdee Change: Use standard boolean toggle buttons for game options toggles. 2025-04-21 16:23:11 +01:00
Peter Nelson d89753b88d Codechange: Add dedicated widget for boolean toggle buttons. 2025-04-21 16:23:11 +01:00
Peter Nelson e3d2d68bd4 Change: Draw boolean toggle as a slider widget.
This improves usability as the slider position indicates the state instead of a red/green colour change.
2025-04-21 16:23:11 +01:00
Rubidium e3858e81dc Codechange: use std::string_view over const std::string& for finding files 2025-04-21 17:20:00 +02:00
frosch 354ad43edb
Codechange: Remove unnecessary string constructions. (#14063) 2025-04-21 16:46:31 +02:00
Peter Nelson e1fdc10227
Fix e114ed357d: Incorrect test of object flags allowed HQ to be removed. (#14062) 2025-04-21 15:45:29 +01:00
Loïc Guilloux 305c892b3a
Change: "setting" console command now shows default value (#14061) 2025-04-21 16:00:37 +02:00
Peter Nelson 788845f731
Change: Allow Double-Ctrl+Click on default size box to clear saved size. (#14055) 2025-04-21 14:16:29 +01:00
Peter Nelson 0cf7048a67
Change: Don't select content when toggling its download status. (#14059)
This improves usability when toggling content sorted by status, as the list position no longer jumps to the now (de)selected item, making it easier to (de)select multiple items.
2025-04-21 13:20:52 +01:00
Peter Nelson 9ff2b4991f
Change: Add scrollbar to infrastructure window. (#14056)
Company infrastructure window will no longer overflow the screen when lots of rail and road types are present.

To further declutter the list, we now only show a value when the count for that item is non-zero.
2025-04-21 08:46:09 +01:00
translators 5502618ac3 Update: Translations from eints
romanian: 1 change by ALEX11BR
2025-04-21 04:45:21 +00:00
Peter Nelson e9a92b8795
Fix: Odd drawing and crash if scrollbar is not tall enough. (#14052)
Under certain conditions the scrollbar "tab" could be too large for the scrollbar, and cause issues.

Caused by an off-by-one in height calculation.
2025-04-20 23:23:52 +01:00
frosch 0efbb3a7a7
Doc: PR template referenced non-existing label. (#14050) 2025-04-20 23:02:33 +02:00
frosch 689f55a0ea
Fix #14044: Negative string parameters from GS were rendered as zero. (#14049)
String parameters are always stored as uint64_t. Negative values are sign-extended to int64_t and then casted to uint64_t.
The same applies to encoded strings. But ScriptText encoded them as int64_t.

Co-authored-by: rubidium42 <rubidium42@users.noreply.github.com>
2025-04-20 23:01:49 +02:00
Rubidium 4e14f0ac3f Codechange: pass network tokens as std::string_view or with move semantics where appropriate 2025-04-20 22:43:24 +02:00
Rubidium c13956a58a Codechange: use std::string_view for connection strings 2025-04-20 22:43:24 +02:00
Rubidium 31433882a4 Codechange: use std::string_view for passing NetworkError strings 2025-04-20 22:43:24 +02:00
frosch 8aa2f6b8a6
Codefix: StringConsumer integer parsing failed for the most negative value, which has no positive equivalent. (#14048) 2025-04-20 22:20:53 +02:00
Peter Nelson fc45bb5a2b
Codechange: Replace bitstuffed VehicleEnterTileStatus. (#14027)
VehicleEnterTileStatus was an bitset-style enum, but bitstuffed with a StationID. However the StationID part was only used by trains, and only in two locations.

Instead, return just the enum bitset. The two places which require the StationID just call GetStationIndex() directly.
2025-04-20 21:10:02 +01:00
frosch cb113cfed0 Codefix: Add missing header includes. 2025-04-20 22:06:18 +02:00
frosch 461b73e21b Codefix: stdafx.h and safeguards.h should be the first and last include in every source file, and not appear in any header file. 2025-04-20 22:06:18 +02:00
frosch 54de376c55 Codechange: Make the squirrel-exporter skip ctor lists. 2025-04-20 21:07:12 +02:00
frosch 6256b55671 Codechange: Make the squirrel-exporter skip function bodies. 2025-04-20 21:07:12 +02:00
Rubidium 26de3404a4 Codechange: use std::string_view for sending chat messages 2025-04-20 13:31:41 +02:00
Rubidium bb259b8e77 Codechange: use std::string_view for sending a remote console command (result) 2025-04-20 13:31:41 +02:00
Rubidium d99edf2bbc Codechange: use std::string_view for kicking/banning 2025-04-20 13:31:41 +02:00
Rubidium a0246bc8a7 Codechange: use std::string_view over std::string for NetworkTextMessage 2025-04-20 13:31:41 +02:00
Rubidium a0e4dab771 Codechange: use std::string_view for NetworkAddress::IsInNetmask of std::string 2025-04-20 13:31:41 +02:00
frosch ff2da0fc73 Codechange: Remove CircularTileSearch. 2025-04-20 12:50:45 +02:00
frosch b956af631e Codechange: Replace CircularTileSearch with SpiralTileSequence. 2025-04-20 12:50:45 +02:00
frosch 0dada5a750 Codechange: Add SpiralTileSequence to iterate over a tile area the same ways as CircularTileSearch. 2025-04-20 12:50:45 +02:00
frosch b9bd7b2cfe Codechange: Confusion of 'radius' and 'diameter' in variable names and comments. 2025-04-20 12:50:45 +02:00
Peter Nelson e43e4327a7
Fix: Incorrect string display for autoreplace wagon removal status. (#14038) 2025-04-20 10:44:37 +01:00
translators ee81313254 Update: Translations from eints
welsh: 1 change by Ansbaradigeidfran
vietnamese: 2 changes by KhoiCanDev
2025-04-20 04:43:37 +00:00
Peter Nelson 2b92d76e9d
Fix e49150f9ca: House picker crashes if selection is not available. (#14030)
This occurs because the extra invalidation in OnInit() also happens on construction, and too early.

Solution is to validate all instead of just position when invalidating in OnInit().
2025-04-19 15:04:18 +01:00
translators d248f45d67 Update: Translations from eints
vietnamese: 7 changes by KhoiCanDev
2025-04-19 04:44:03 +00:00
frosch 43ea6c9b88 Codechange: Turn AyStar into an actual class with virtual methods instead of function pointers. 2025-04-19 00:24:15 +02:00
frosch 97ead8e241 Codechange: Remove unused options from AyStar. 2025-04-19 00:24:15 +02:00
frosch 53899c3c21 Codechange: Replace vehicle viewport hash macros with functions. 2025-04-18 23:41:37 +02:00
frosch cde350dc01 Codechange: Replace macros GENERAL_SPRITE_COLOUR and COMPANY_SPRITE_COLOUR with functions GetColourPalette and GetCompanyPalette. 2025-04-18 23:41:37 +02:00
frosch c2c5dae760 Codechange: Turn GREY_SCALE macro into constexpr function. 2025-04-18 23:41:37 +02:00
frosch 8f335a84cf Codechange: Turn GetCustom(Vehicle|Rotor)(Sprite|Icon) macros into functions. 2025-04-18 23:41:37 +02:00
frosch 8f8e997575 Codechange: Replace local macro with lambda. 2025-04-18 23:41:37 +02:00
frosch 68016031cf Codechange: Turn macros GetCompanyHQSize and IncreaseCompanyHQSize into functions. 2025-04-18 23:41:37 +02:00
frosch 0eb6964311 Codechange: Change ScreenshotCallback into a std::function, so there is no need for void* user data. 2025-04-18 22:43:41 +02:00
frosch c09e825e0b Codechange: Change SetDateCallback into a std::function, so there is no need for void* user data. 2025-04-18 22:43:41 +02:00
frosch 0d4588688f Codechange: Manage script event queue using smart pointers. 2025-04-18 19:47:28 +02:00
frosch b9f4ef3d78 Codechange: Move ScriptStorage constructor into source file, so private members can have partially incomplete types. 2025-04-18 19:47:28 +02:00
frosch af14809697
Codechange: Add filename and line number to errors/warnings of the squirrel-exporters. (#14031) 2025-04-18 19:43:32 +02:00
frosch 50252cb5df
Codechange: Ini(Load|Save)WindowSettings expect a WindowDesc*, no void*. (#14029) 2025-04-18 18:44:58 +02:00
Peter Nelson 394adb654e
Codechange: Move GUI parts of badges to a separate file. (#14023) 2025-04-18 17:20:31 +01:00
Peter Nelson 67d6089f39
Change: Don't replace stripped control codes with '?' for scripts. (#14028) 2025-04-18 17:20:08 +01:00
frosch 45917dbaa3 Codechange: Remove unused macro strncasecmp. 2025-04-18 17:16:48 +02:00
frosch 84e175ce63 Codechange: Determine array length using 'std::size' instead of using a separate constant. 2025-04-18 17:16:48 +02:00
frosch 7cbf4f5560 Codechange: Expand the single usage of the macro CLRBITS. 2025-04-18 17:16:48 +02:00
frosch d97936e77a Codechange: Replace ALIGN macro with C++11 alignas specifier. 2025-04-18 17:16:48 +02:00
frosch f82e172610 Codechange: Expand and remove DEF_CONSOLE_CMD and DEF_CONSOLE_HOOK macros. 2025-04-18 17:16:48 +02:00
frosch 42deccc4f5 Codechange: Merge (IsOn|Toggle)(Snow|Desert) into (IsOn|Toggle)SnowOrDesert. 2025-04-18 16:33:26 +02:00
frosch 252376ce3e Codechange: Rename DrawRoadAsSnowDesert to DrawRoadAsSnowOrDesert to be consistent with other functions. 2025-04-18 16:33:26 +02:00
frosch 26db4ccf09
Codechange: Turn bit-stuffed FiosType enum into a struct. (#14019) 2025-04-18 15:20:55 +02:00
frosch b862d4937f
Codechange: Turn custom vehicle spritenums into enum, and use them consistently. (#14022) 2025-04-18 15:19:28 +02:00
Peter Nelson 2c59838acb
Codechange: (re)set multiple bitset flags in one call. (#14017) 2025-04-18 14:07:57 +01:00
frosch 31e716449d
Codechange: Change StationNameInformation to not use macros. (#14020) 2025-04-18 15:06:46 +02:00
frosch 5aed046d11
Fix: [NewGRF] Strange things happened, when using the synchronised tile loop animation trigger for houses. (#14011) 2025-04-17 12:15:49 +02:00
translators 421f202539 Update: Translations from eints
luxembourgish: 103 changes by phreeze83
latvian: 1 change by lexuslatvia
2025-04-17 04:45:26 +00:00
Peter Nelson 1f83ea41fc
Fix: [NewGRF] PrepareLayout worked on a copy of the data resulting in bad sprite layouts. (#14013) 2025-04-16 21:27:36 +00:00
Peter Nelson 378ea52ac6 Codechange: Use EnumBitSet for CzechChooseFlags. 2025-04-16 19:44:28 +01:00
Peter Nelson ea0817390f Codechange: Use EnumBitSet for CzechAllowFlags. 2025-04-16 19:44:28 +01:00
Peter Nelson 6ea10edef8
Codechange: Use std::unique_ptrs for handling station cargo display. (#14009)
Replaces manual management of raw pointers.
2025-04-16 19:43:45 +01:00
Peter Nelson a281ac4674 Codefix: Information for NewGRF specs remained duplicated after loading.
After loading airports+tiles, industries+tiles, houses and objects, their specs are copied from the NewGRF's loading storage to the final global storage.

Instead, move the specs to the their new storage, and clear the NewGRF's storage once done. (Stations and RoadStops are different, and the NewGRF's storage is the final storage location.)
2025-04-16 19:43:07 +01:00
Peter Nelson f9ab492e64 Codechange: Pass HouseSpec by reference to IsHouseSpecValid(). 2025-04-16 19:43:07 +01:00
translators b57f3262ec Update: Translations from eints
spanish: 101 changes by MontyMontana
2025-04-16 04:44:48 +00:00
Peter Nelson fa0814e257
Codefix: Codestyle consistency fixes. (#14008) 2025-04-15 20:57:13 +00:00
frosch 03ed59a004 Codechange: Turn AnimationStatus into an enum class. 2025-04-15 20:42:44 +02:00
frosch 47f0f4dd9e Fix: [NewGRF] Animation speed properties of houses and stations had wrong default. 2025-04-15 20:42:44 +02:00
818 changed files with 23627 additions and 22475 deletions

View File

@ -50,7 +50,6 @@ Describe here
Some things are not automated, and forgotten often. This list is a reminder for the reviewers.
* The bug fix is important enough to be backported? (label: 'backport requested')
* This PR touches english.txt or translations? Check the [guidelines](https://github.com/OpenTTD/OpenTTD/blob/master/docs/eints.md)
* This PR affects the save game format? (label 'savegame upgrade')
* This PR affects the GS/AI API? (label 'needs review: Script API')
* ai_changelog.hpp, game_changelog.hpp need updating.
* The compatibility wrappers (compat_*.nut) need updating.

View File

@ -158,7 +158,7 @@ def scan_source_files(path, strings_found):
# Most files we can just open, but some use magic, that requires the
# G++ preprocessor before we can make sense out of it.
if new_path == "src/table/cargo_const.h":
p = subprocess.run(["g++", "-E", new_path], stdout=subprocess.PIPE)
p = subprocess.run(["g++", "-E", "-DCHECK_UNUSED_STRINGS", new_path], stdout=subprocess.PIPE)
output = p.stdout.decode()
else:
with open(new_path) as fp:

View File

@ -86,7 +86,7 @@ jobs:
echo "::endgroup::"
- name: Import code signing certificates
uses: Apple-Actions/import-codesign-certs@v3
uses: Apple-Actions/import-codesign-certs@v5
with:
# The certificates in a PKCS12 file encoded as a base64 string
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}

View File

@ -77,7 +77,7 @@ jobs:
curl -L https://cdn.openttd.org/openmsx-releases/0.4.2/openmsx-0.4.2-all.zip -o openmsx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
echo "::group::Unpack OpenMSX"
unzip openmsx-all.zip
tar xf openmsx-*.tar
echo "::endgroup::"

View File

@ -37,12 +37,10 @@ Both 'stable' and 'nightly' versions are available for download:
OpenTTD is also available for free on [Steam](https://store.steampowered.com/app/1536610/OpenTTD/), [GOG.com](https://www.gog.com/game/openttd), and the [Microsoft Store](https://www.microsoft.com/p/openttd-official/9ncjg5rvrr1c). On some platforms OpenTTD will be available via your OS package manager or a similar service.
## 1.2) OpenTTD gameplay manual
OpenTTD has a [community-maintained wiki](https://wiki.openttd.org/), including a gameplay manual and tips.
## 1.3) Supported platforms
OpenTTD has been ported to several platforms and operating systems.
@ -56,6 +54,7 @@ The currently supported platforms are:
Other platforms may also work (in particular various BSD systems), but we don't actively test or maintain these.
### 1.3.1) Legacy support
Platforms, languages and compilers change.
We'll keep support going on old platforms as long as someone is interested in supporting them, except where it means the project can't move forward to keep up with language and compiler features.
@ -72,7 +71,6 @@ For some platforms these will be downloaded during the installation process if r
For some platforms, you will need to refer to [the installation guide](https://wiki.openttd.org/en/Manual/Installation).
### 1.4.1) Free graphics and sound files
The free data files, split into OpenGFX for graphics, OpenSFX for sounds and
@ -85,7 +83,6 @@ OpenMSX for music can be found at:
Please follow the readme of these packages about the installation procedure.
The Windows installer can optionally download and install these packages.
### 1.4.2) Original Transport Tycoon Deluxe graphics and sound files
If you want to play with the original Transport Tycoon Deluxe data files you have to copy the data files from the CD-ROM into the baseset/ directory.
@ -100,7 +97,6 @@ You need to copy the following files:
- trgir.grf or TRGI.GRF
- trgtr.grf or TRGT.GRF
### 1.4.3) Original Transport Tycoon Deluxe music
If you want the Transport Tycoon Deluxe music, copy the appropriate files from the original game into the baseset folder.
@ -108,7 +104,6 @@ If you want the Transport Tycoon Deluxe music, copy the appropriate files from t
- TTD for DOS: The GM.CAT file
- Transport Tycoon Original: The GM.CAT file, but rename it to GM-TTO.CAT
## 1.5) Add-on content / mods
OpenTTD features multiple types of add-on content, which modify gameplay in different ways.
@ -117,7 +112,6 @@ Most types of add-on content can be downloaded within OpenTTD via the 'Check Onl
Add-on content can also be installed manually, but that's more complicated; the [OpenTTD wiki](https://wiki.openttd.org/) may offer help with that, or the [OpenTTD directory structure guide](./docs/directory_structure.md).
### 1.5.1) Social Integration
OpenTTD has the ability to load plugins to integrate with Social Platforms like Steam, Discord, etc.
@ -126,7 +120,6 @@ To enable such integration, the plugin for the specific platform has to be downl
See [OpenTTD's website](https://www.openttd.org), under Downloads, for what plugins are available.
### 1.6) OpenTTD directories
OpenTTD uses its own directory structure to store game data, add-on content etc.
@ -137,7 +130,6 @@ For more information, see the [directory structure guide](./docs/directory_struc
If you want to compile OpenTTD from source, instructions can be found in [COMPILING.md](./COMPILING.md).
## 2.0) Contact and Community
'Official' channels
@ -160,12 +152,10 @@ You can play OpenTTD with others, either cooperatively or competitively.
See the [multiplayer documentation](./docs/multiplayer.md) for more details.
### 2.2) Contributing to OpenTTD
We welcome contributors to OpenTTD. More information for contributors can be found in [CONTRIBUTING.md](./CONTRIBUTING.md)
### 2.3) Reporting bugs
Good bug reports are very helpful. We have a [guide to reporting bugs](./CONTRIBUTING.md#bug-reports) to help with this.
@ -173,12 +163,10 @@ Good bug reports are very helpful. We have a [guide to reporting bugs](./CONTRI
Desyncs in multiplayer are complex to debug and report (some software development skils are required).
Instructions can be found in [debugging and reporting desyncs](./docs/debugging_desyncs.md).
### 2.4) Translating
OpenTTD is translated into many languages. Translations are added and updated via the [online translation tool](https://translator.openttd.org).
## 3.0) Licensing
OpenTTD is licensed under the GNU General Public License version 2.0.
@ -215,6 +203,6 @@ See `src/3rdparty/openttd_social_integration_api/LICENSE` for the complete licen
The atomic datatype support detection in `cmake/3rdparty/llvm/CheckAtomic.cmake` is licensed under the Apache 2.0 license.
See `cmake/3rdparty/llvm/LICENSE.txt` for the complete license text.
## 4.0 Credits
## 4.0) Credits
See [CREDITS.md](./CREDITS.md)

View File

@ -36,3 +36,11 @@ AITown.FoundTown <- function(tile, size, city, layout, name) { return AITown.Fou
AIVehicle.SetNameCompat14 <- AIVehicle.SetName;
AIVehicle.SetName <- function(id, name) { return AIVehicle.SetNameCompat14(id, AICompat14.Text(name)); }
AIObject.constructorCompat14 <- AIObject.constructor;
foreach(name, object in CompatScriptRootTable) {
if (type(object) != "class") continue;
if (!object.rawin("constructor")) continue;
if (object.constructor != AIObject.constructorCompat14) continue;
object.constructor <- function() : (name) { AILog.Error("'" + name + "' is not instantiable"); }
}

View File

@ -9,6 +9,9 @@
GSBridge.GetBridgeID <- GSBridge.GetBridgeType;
/* Emulate old GSText parameter padding behaviour */
GSText.SCRIPT_TEXT_MAX_PARAMETERS <- 20;
class GSCompat14 {
function Text(text)
{
@ -78,3 +81,11 @@ GSTown.FoundTown <- function(tile, size, city, layout, name) { return GSTown.Fou
GSVehicle.SetNameCompat14 <- GSVehicle.SetName;
GSVehicle.SetName <- function(id, name) { return GSVehicle.SetNameCompat14(id, GSCompat14.Text(name)); }
GSObject.constructorCompat14 <- GSObject.constructor;
foreach(name, object in CompatScriptRootTable) {
if (type(object) != "class") continue;
if (!object.rawin("constructor")) continue;
if (object.constructor != GSObject.constructorCompat14) continue;
object.constructor <- function() : (name) { GSLog.Error("'" + name + "' is not instantiable"); }
}

View File

@ -17,41 +17,48 @@ if(NOT APILC)
endif()
macro(dump_fileheader)
get_filename_component(SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE}" NAME)
string(APPEND SQUIRREL_EXPORT "\n#include \"../${SCRIPT_API_FILE_NAME}\"")
get_filename_component(SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE}" NAME_WE)
string(APPEND SQUIRREL_EXPORT "\n#include \"../${SCRIPT_API_FILE_NAME}.hpp\"")
if(NOT "${APIUC}" STREQUAL "Template")
string(REPLACE "script_" "template_" SCRIPT_API_FILE_NAME "${SCRIPT_API_FILE_NAME}")
string(APPEND SQUIRREL_EXPORT "\n#include \"../template/${SCRIPT_API_FILE_NAME}.sq\"")
string(APPEND SQUIRREL_EXPORT "\n#include \"../template/${SCRIPT_API_FILE_NAME}.sq.hpp\"")
endif()
endmacro()
macro(open_namespace)
if(NOT NAMESPACE_OPENED)
string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {")
set(NAMESPACE_OPENED TRUE)
endif()
endmacro()
macro(dump_class_templates NAME)
string(REGEX REPLACE "^Script" "" REALNAME ${NAME})
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} *> { static inline ${NAME} *Get(HSQUIRRELVM vm, int index) { return static_cast<${NAME} *>(Squirrel::GetRealInstance(vm, index, \"${REALNAME}\")); } };")
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} &> { static inline ${NAME} &Get(HSQUIRRELVM vm, int index) { return *static_cast<${NAME} *>(Squirrel::GetRealInstance(vm, index, \"${REALNAME}\")); } };")
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<const ${NAME} *> { static inline const ${NAME} *Get(HSQUIRRELVM vm, int index) { return static_cast<${NAME} *>(Squirrel::GetRealInstance(vm, index, \"${REALNAME}\")); } };")
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<const ${NAME} &> { static inline const ${NAME} &Get(HSQUIRRELVM vm, int index) { return *static_cast<${NAME} *>(Squirrel::GetRealInstance(vm, index, \"${REALNAME}\")); } };")
string(APPEND SQUIRREL_EXPORT "\n\ttemplate <> struct Param<${NAME} *> { static inline ${NAME} *Get(HSQUIRRELVM vm, int index) { return static_cast<${NAME} *>(Squirrel::GetRealInstance(vm, index, \"${REALNAME}\")); } };")
string(APPEND SQUIRREL_EXPORT "\n\ttemplate <> struct Param<${NAME} &> { static inline ${NAME} &Get(HSQUIRRELVM vm, int index) { return *static_cast<${NAME} *>(Squirrel::GetRealInstance(vm, index, \"${REALNAME}\")); } };")
string(APPEND SQUIRREL_EXPORT "\n\ttemplate <> struct Param<const ${NAME} *> { static inline const ${NAME} *Get(HSQUIRRELVM vm, int index) { return static_cast<${NAME} *>(Squirrel::GetRealInstance(vm, index, \"${REALNAME}\")); } };")
string(APPEND SQUIRREL_EXPORT "\n\ttemplate <> struct Param<const ${NAME} &> { static inline const ${NAME} &Get(HSQUIRRELVM vm, int index) { return *static_cast<${NAME} *>(Squirrel::GetRealInstance(vm, index, \"${REALNAME}\")); } };")
if("${NAME}" STREQUAL "ScriptEvent")
string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };")
string(APPEND SQUIRREL_EXPORT "\n\ttemplate <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };")
elseif("${NAME}" STREQUAL "ScriptText")
string(APPEND SQUIRREL_EXPORT "\n")
string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<Text *> {")
string(APPEND SQUIRREL_EXPORT "\n static inline Text *Get(HSQUIRRELVM vm, int index) {")
string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_INSTANCE) {")
string(APPEND SQUIRREL_EXPORT "\n return Param<ScriptText *>::Get(vm, index);")
string(APPEND SQUIRREL_EXPORT "\n }")
string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_STRING) {")
string(APPEND SQUIRREL_EXPORT "\n return new RawText(Param<const std::string &>::Get(vm, index));")
string(APPEND SQUIRREL_EXPORT "\n }")
string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_NULL) {")
string(APPEND SQUIRREL_EXPORT "\n return nullptr;")
string(APPEND SQUIRREL_EXPORT "\n }")
string(APPEND SQUIRREL_EXPORT "\n throw sq_throwerror(vm, fmt::format(\"parameter {} has an invalid type ; expected: 'Text'\", index - 1));")
string(APPEND SQUIRREL_EXPORT "\n }")
string(APPEND SQUIRREL_EXPORT "\n };")
string(APPEND SQUIRREL_EXPORT "\n\ttemplate <> struct Param<Text *> {")
string(APPEND SQUIRREL_EXPORT "\n\t\tstatic inline Text *Get(HSQUIRRELVM vm, int index) {")
string(APPEND SQUIRREL_EXPORT "\n\t\t\tif (sq_gettype(vm, index) == OT_INSTANCE) {")
string(APPEND SQUIRREL_EXPORT "\n\t\t\t\treturn Param<ScriptText *>::Get(vm, index);")
string(APPEND SQUIRREL_EXPORT "\n\t\t\t}")
string(APPEND SQUIRREL_EXPORT "\n\t\t\tif (sq_gettype(vm, index) == OT_STRING) {")
string(APPEND SQUIRREL_EXPORT "\n\t\t\t\treturn new RawText(Param<const std::string &>::Get(vm, index));")
string(APPEND SQUIRREL_EXPORT "\n\t\t\t}")
string(APPEND SQUIRREL_EXPORT "\n\t\t\tif (sq_gettype(vm, index) == OT_NULL) {")
string(APPEND SQUIRREL_EXPORT "\n\t\t\t\treturn nullptr;")
string(APPEND SQUIRREL_EXPORT "\n\t\t\t}")
string(APPEND SQUIRREL_EXPORT "\n\t\t\tthrow sq_throwerror(vm, fmt::format(\"parameter {} has an invalid type ; expected: 'Text'\", index - 1));")
string(APPEND SQUIRREL_EXPORT "\n\t\t}")
string(APPEND SQUIRREL_EXPORT "\n\t};")
else()
string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };")
string(APPEND SQUIRREL_EXPORT "\n\ttemplate <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };")
endif()
endmacro()
@ -66,7 +73,6 @@ macro(reset_reader)
unset(STATIC_METHODS)
unset(CLS)
unset(START_SQUIRREL_DEFINE_ON_NEXT_LINE)
set(CLS_LEVEL 0)
unset(CLS_IN_API)
endmacro()
@ -75,6 +81,9 @@ reset_reader()
file(STRINGS "${SCRIPT_API_FILE}" SOURCE_LINES)
set(NUM_LINE 0)
set(CLS_LEVEL 0)
set(BRACE_LEVEL 0)
macro(doxygen_check)
if(NOT "${DOXYGEN_SKIP}" STREQUAL "")
message(FATAL_ERROR "${SCRIPT_API_FILE}:${NUM_LINE}: a DOXYGEN_API block was not properly closed")
@ -110,7 +119,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
continue()
endif()
if("${LINE}" MATCHES "^([ ]*)\\* @api (.*)$")
if("${LINE}" MATCHES "^([\t ]*)\\* @api (.*)$")
set(LINE ${CMAKE_MATCH_2})
# By default, classes are not selected
if(NOT CLS_LEVEL)
@ -148,22 +157,28 @@ foreach(LINE IN LISTS SOURCE_LINES)
continue()
endif()
# Count braces to skip function bodies
string(REGEX REPLACE "[^{]" "" OPENING_BRACES "${LINE}")
string(LENGTH "${OPENING_BRACES}" OPENING_BRACES)
string(REGEX REPLACE "[^}]" "" CLOSING_BRACES "${LINE}")
string(LENGTH "${CLOSING_BRACES}" CLOSING_BRACES)
math(EXPR BRACE_LEVEL "${BRACE_LEVEL} + ${OPENING_BRACES} - ${CLOSING_BRACES}")
# Ignore forward declarations of classes
if("${LINE}" MATCHES "^( *)class(.*);")
if("${LINE}" MATCHES "^(\t*)class(.*);")
continue()
endif()
# We only want to have public functions exported for now
if("${LINE}" MATCHES "^( *)class (.*) (: public|: protected|: private|:) ([^ ]*)")
if("${LINE}" MATCHES "^(\t*)class (.*) (: public|: protected|: private|:) ([^ ]*)")
if(NOT CLS_LEVEL)
if(NOT DEFINED API_SELECTED)
message(WARNING "Class '${CMAKE_MATCH_2}' has no @api. It won't be published to any API.")
message(WARNING "${SCRIPT_API_FILE}:${NUM_LINE}: Class '${CMAKE_MATCH_2}' has no @api. It won't be published to any API.")
set(API_SELECTED FALSE)
endif()
unset(IS_PUBLIC)
unset(CLS_PARAM_0)
set(CLS_PARAM_1 1)
set(CLS_PARAM_2 "x")
unset(CLS_PARAMS)
set(CLS_TYPES "x")
set(CLS_IN_API ${API_SELECTED})
unset(API_SELECTED)
set(CLS "${CMAKE_MATCH_2}")
@ -181,19 +196,19 @@ foreach(LINE IN LISTS SOURCE_LINES)
math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1")
continue()
endif()
if("${LINE}" MATCHES "^( *)public")
if("${LINE}" MATCHES "^(\t*)public")
if(CLS_LEVEL EQUAL 1)
set(IS_PUBLIC TRUE)
endif()
continue()
endif()
if("${LINE}" MATCHES "^( *)protected")
if("${LINE}" MATCHES "^(\t*)protected")
if(CLS_LEVEL EQUAL 1)
unset(IS_PUBLIC)
endif()
continue()
endif()
if("${LINE}" MATCHES "^( *)private")
if("${LINE}" MATCHES "^(\t*)private")
if(CLS_LEVEL EQUAL 1)
unset(IS_PUBLIC)
endif()
@ -221,7 +236,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
endif()
# We need to make specialized conversions for structs
if("${LINE}" MATCHES "^( *)struct ([^ ]*)")
if("${LINE}" MATCHES "^(\t*)struct ([^ ]*)")
math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1")
# Check if we want to publish this struct
@ -243,7 +258,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
endif()
# We need to make specialized conversions for enums
if("${LINE}" MATCHES "^( *)enum ([^ ]*)")
if("${LINE}" MATCHES "^(\t*)enum ([^ ]*)")
math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1")
# Check if we want to publish this enum
@ -266,7 +281,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
endif()
# Maybe the end of the class, if so we can start with the Squirrel export pretty soon
if("${LINE}" MATCHES "};")
if(BRACE_LEVEL LESS CLS_LEVEL)
math(EXPR CLS_LEVEL "${CLS_LEVEL} - 1")
if(CLS_LEVEL)
unset(IN_ENUM)
@ -280,7 +295,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
endif()
# Empty/white lines. When we may do the Squirrel export, do that export.
if("${LINE}" MATCHES "^([ ]*)$")
if("${LINE}" MATCHES "^([ \t]*)$")
if(NOT START_SQUIRREL_DEFINE_ON_NEXT_LINE)
continue()
endif()
@ -304,33 +319,17 @@ foreach(LINE IN LISTS SOURCE_LINES)
string(APPEND SQUIRREL_EXPORT "\n")
if("${APIUC}" STREQUAL "Template")
# First check whether we have enums to print
if(DEFINED ENUMS)
if(NOT NAMESPACE_OPENED)
string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {")
set(NAMESPACE_OPENED TRUE)
endif()
endif()
# Then check whether we have structs/classes to print
if(DEFINED STRUCTS)
if(NOT NAMESPACE_OPENED)
string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {")
set(NAMESPACE_OPENED TRUE)
endif()
string(APPEND SQUIRREL_EXPORT "\n /* Allow inner classes/structs to be used as Squirrel parameters */")
open_namespace()
string(APPEND SQUIRREL_EXPORT "\n\t/* Allow inner classes/structs to be used as Squirrel parameters */")
foreach(STRUCT IN LISTS STRUCTS)
dump_class_templates(${STRUCT})
endforeach()
endif()
if(NOT NAMESPACE_OPENED)
string(APPEND SQUIRREL_EXPORT "\nnamespace SQConvert {")
set(NAMESPACE_OPENED TRUE)
else()
string(APPEND SQUIRREL_EXPORT "\n")
endif()
string(APPEND SQUIRREL_EXPORT "\n /* Allow ${CLS} to be used as Squirrel parameter */")
open_namespace()
string(APPEND SQUIRREL_EXPORT "\n\t/* Allow ${CLS} to be used as Squirrel parameter */")
dump_class_templates(${CLS})
string(APPEND SQUIRREL_EXPORT "\n} // namespace SQConvert")
@ -340,23 +339,23 @@ foreach(LINE IN LISTS SOURCE_LINES)
endif()
string(APPEND SQUIRREL_EXPORT "\n")
string(APPEND SQUIRREL_EXPORT "\ntemplate <> SQInteger PushClassName<${CLS}, ScriptType::${APIUC}>(HSQUIRRELVM vm) { sq_pushstring(vm, \"${API_CLS}\", -1); return 1; }")
string(APPEND SQUIRREL_EXPORT "\ntemplate <> SQInteger PushClassName<${CLS}, ScriptType::${APIUC}>(HSQUIRRELVM vm) { sq_pushstring(vm, \"${API_CLS}\"); return 1; }")
string(APPEND SQUIRREL_EXPORT "\n")
# Then do the registration functions of the class.
string(APPEND SQUIRREL_EXPORT "\nvoid SQ${API_CLS}_Register(Squirrel *engine)")
string(APPEND SQUIRREL_EXPORT "\nvoid SQ${API_CLS}_Register(Squirrel &engine)")
string(APPEND SQUIRREL_EXPORT "\n{")
string(APPEND SQUIRREL_EXPORT "\n DefSQClass<${CLS}, ScriptType::${APIUC}> SQ${API_CLS}(\"${API_CLS}\");")
string(APPEND SQUIRREL_EXPORT "\n\tDefSQClass<${CLS}, ScriptType::${APIUC}> SQ${API_CLS}(\"${API_CLS}\");")
if("${SUPER_CLS}" STREQUAL "Text")
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.PreRegister(engine);")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.PreRegister(engine);")
else()
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.PreRegister(engine, \"${API_SUPER_CLS}\");")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.PreRegister(engine, \"${API_SUPER_CLS}\");")
endif()
if(NOT "${SUPER_CLS}" MATCHES "^ScriptEvent")
if("${CLS_PARAM_2}" STREQUAL "v")
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.AddSQAdvancedConstructor(engine);")
if((DEFINED CLS_PARAMS OR DEFINED METHODS) AND NOT "${SUPER_CLS}" MATCHES "^ScriptEvent" AND NOT "${CLS}" STREQUAL "ScriptEvent")
if("${CLS_TYPES}" STREQUAL "v")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.AddSQAdvancedConstructor(engine);")
else()
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.AddConstructor<void (${CLS}::*)(${CLS_PARAM_0}), ${CLS_PARAM_1}>(engine, \"${CLS_PARAM_2}\");")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.AddConstructor<void (${CLS}::*)(${CLS_PARAMS})>(engine, \"${CLS_TYPES}\");")
endif()
endif()
string(APPEND SQUIRREL_EXPORT "\n")
@ -376,7 +375,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
foreach(i RANGE ${LEN})
string(APPEND SPACES " ")
endforeach()
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQConst(engine, ${CLS}::${ENUM_VALUE},${SPACES}\"${ENUM_VALUE}\");")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQConst(engine, ${CLS}::${ENUM_VALUE},${SPACES}\"${ENUM_VALUE}\");")
endforeach()
if(MLEN)
string(APPEND SQUIRREL_EXPORT "\n")
@ -397,7 +396,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
foreach(i RANGE ${LEN})
string(APPEND SPACES " ")
endforeach()
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQConst(engine, ${CLS}::${CONST_VALUE},${SPACES}\"${CONST_VALUE}\");")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQConst(engine, ${CLS}::${CONST_VALUE},${SPACES}\"${CONST_VALUE}\");")
endforeach()
if(MLEN)
string(APPEND SQUIRREL_EXPORT "\n")
@ -423,7 +422,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
foreach(i RANGE ${LEN})
string(APPEND SPACES " ")
endforeach()
string(APPEND SQUIRREL_EXPORT "\n ScriptError::RegisterErrorMap(${ENUM_STRING},${SPACES}${CLS}::${ENUM_ERROR});")
string(APPEND SQUIRREL_EXPORT "\n\tScriptError::RegisterErrorMap(${ENUM_STRING},${SPACES}${CLS}::${ENUM_ERROR});")
endforeach()
if(MLEN)
string(APPEND SQUIRREL_EXPORT "\n")
@ -444,7 +443,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
foreach(i RANGE ${LEN})
string(APPEND SPACES " ")
endforeach()
string(APPEND SQUIRREL_EXPORT "\n ScriptError::RegisterErrorMapString(${CLS}::${ENUM_ERROR_TO_STRING},${SPACES}\"${ENUM_ERROR_TO_STRING}\");")
string(APPEND SQUIRREL_EXPORT "\n\tScriptError::RegisterErrorMapString(${CLS}::${ENUM_ERROR_TO_STRING},${SPACES}\"${ENUM_ERROR_TO_STRING}\");")
endforeach()
if(MLEN)
string(APPEND SQUIRREL_EXPORT "\n")
@ -463,8 +462,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
foreach(STATIC_METHOD IN LISTS STATIC_METHODS)
string(REPLACE ":" ";" STATIC_METHOD "${STATIC_METHOD}")
list(GET STATIC_METHOD 0 FUNCNAME)
list(GET STATIC_METHOD 1 ARGC)
list(GET STATIC_METHOD 2 TYPES)
list(GET STATIC_METHOD 1 TYPES)
string(LENGTH "${FUNCNAME}" LEN)
math(EXPR LEN "${MLEN} - ${LEN}")
if("${TYPES}" STREQUAL "v")
@ -479,9 +477,9 @@ foreach(LINE IN LISTS SOURCE_LINES)
string(APPEND SPACES " ")
endforeach()
if("${TYPES}" STREQUAL "v")
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQAdvancedStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQAdvancedStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");")
else()
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}${ARGC}, \"${TYPES}\");")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}\"${TYPES}\");")
endif()
endforeach()
if(MLEN)
@ -501,8 +499,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
foreach(METHOD IN LISTS METHODS)
string(REPLACE ":" ";" METHOD "${METHOD}")
list(GET METHOD 0 FUNCNAME)
list(GET METHOD 1 ARGC)
list(GET METHOD 2 TYPES)
list(GET METHOD 1 TYPES)
string(LENGTH "${FUNCNAME}" LEN)
math(EXPR LEN "${MLEN} - ${LEN}")
if("${TYPES}" STREQUAL "v")
@ -517,16 +514,16 @@ foreach(LINE IN LISTS SOURCE_LINES)
string(APPEND SPACES " ")
endforeach()
if("${TYPES}" STREQUAL "v")
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQAdvancedMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQAdvancedMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");")
else()
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.DefSQMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}${ARGC}, \"${TYPES}\");")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}\"${TYPES}\");")
endif()
endforeach()
if(MLEN)
string(APPEND SQUIRREL_EXPORT "\n")
endif()
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.PostRegister(engine);")
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.PostRegister(engine);")
string(APPEND SQUIRREL_EXPORT "\n}")
reset_reader()
@ -539,9 +536,13 @@ foreach(LINE IN LISTS SOURCE_LINES)
continue()
endif()
if(NOT BRACE_LEVEL EQUAL CLS_LEVEL)
continue()
endif()
# Add enums
if(IN_ENUM)
string(REGEX MATCH "([^, ]+)" ENUM_VALUE "${LINE}")
string(REGEX MATCH "([^,\t ]+)" ENUM_VALUE "${LINE}")
list(APPEND ENUM_VALUES "${ENUM_VALUE}")
# Check if this a special error enum
@ -549,12 +550,12 @@ foreach(LINE IN LISTS SOURCE_LINES)
if("${ENUM}" MATCHES ".*::ErrorMessages")
# syntax:
# enum ErrorMessages {
# ERR_SOME_ERROR, // [STR_ITEM1, STR_ITEM2, ...]
#\tERR_SOME_ERROR,\t// [STR_ITEM1, STR_ITEM2, ...]
# }
# Set the mappings
if("${LINE}" MATCHES "\\[(.*)\\]")
string(REGEX REPLACE "[ ]" "" MAPPINGS "${CMAKE_MATCH_1}")
string(REGEX REPLACE "[ \t]" "" MAPPINGS "${CMAKE_MATCH_1}")
string(REPLACE "," ";" MAPPINGS "${MAPPINGS}")
foreach(MAPPING IN LISTS MAPPINGS)
@ -568,11 +569,11 @@ foreach(LINE IN LISTS SOURCE_LINES)
endif()
# Add a const (non-enum) value
if("${LINE}" MATCHES "^[ ]*static const [^ ]+ ([^ ]+) = -?\\(?[^ ]*\\)?[^ ]+;")
if("${LINE}" MATCHES "^[ \t]*static const [^ ]+ ([^ ]+) = -?\\(?[^ ]*\\)?[^ ]+;")
list(APPEND CONST_VALUES "${CMAKE_MATCH_1}")
continue()
endif()
if("${LINE}" MATCHES "^[ ]*static constexpr [^ ]+ ([^ ]+) = -?\\(?[^ ]*\\)?[^ ]+;")
if("${LINE}" MATCHES "^[ \t]*static constexpr [^ ]+ ([^ ]+) = -?\\(?[^ ]*\\)?[^ ]+;")
list(APPEND CONST_VALUES "${CMAKE_MATCH_1}")
continue()
endif()
@ -584,41 +585,43 @@ foreach(LINE IN LISTS SOURCE_LINES)
endif()
if("${LINE}" MATCHES "~")
if(DEFINED API_SELECTED)
message(WARNING "Destructor for '${CLS}' has @api. Tag ignored.")
message(WARNING "${SCRIPT_API_FILE}:${NUM_LINE}: Destructor for '${CLS}' has @api. Tag ignored.")
unset(API_SELECTED)
endif()
continue()
endif()
unset(IS_STATIC)
if("${LINE}" MATCHES "static")
if("${LINE}" MATCHES "static ")
set(IS_STATIC TRUE)
endif()
string(REGEX REPLACE "(virtual|static|const)[ ]+" "" LINE "${LINE}")
string(REGEX REPLACE "(virtual|static|const)[ \t]+" "" LINE "${LINE}")
string(REGEX REPLACE "{.*" "" LINE "${LINE}")
set(PARAM_S "${LINE}")
string(REGEX REPLACE "\\*" "" LINE "${LINE}")
string(REGEX REPLACE "\\(.*" "" LINE "${LINE}")
string(REGEX REPLACE ".*\\(" "" PARAM_S "${PARAM_S}")
# Parameters start at first "(". Further "(" will appear in ctor lists.
string(REGEX MATCH "\\(.*" PARAM_S "${PARAM_S}")
string(REGEX REPLACE "\\).*" "" PARAM_S "${PARAM_S}")
string(REGEX REPLACE "^\\(" "" PARAM_S "${PARAM_S}")
string(REGEX MATCH "([^ ]+)( ([^ ]+))?" RESULT "${LINE}")
string(REGEX MATCH "([^ \t]+)( ([^ ]+))?" RESULT "${LINE}")
set(FUNCTYPE "${CMAKE_MATCH_1}")
set(FUNCNAME "${CMAKE_MATCH_3}")
if("${FUNCTYPE}" STREQUAL "${CLS}" AND NOT FUNCNAME)
if(DEFINED API_SELECTED)
message(WARNING "Constructor for '${CLS}' has @api. Tag ignored.")
message(WARNING "${SCRIPT_API_FILE}:${NUM_LINE}: Constructor for '${CLS}' has @api. Tag ignored.")
unset(API_SELECTED)
endif()
set(CLS_PARAM_0 "${PARAM_S}")
set(CLS_PARAMS "${PARAM_S}")
if(NOT PARAM_S)
continue()
endif()
elseif(NOT FUNCNAME)
continue()
endif()
endif()
string(REPLACE "," ";" PARAMS "${PARAM_S}")
if(IS_STATIC)
@ -627,9 +630,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
set(TYPES "x")
endif()
set(LEN 1)
foreach(PARAM IN LISTS PARAMS)
math(EXPR LEN "${LEN} + 1")
string(STRIP "${PARAM}" PARAM)
if("${PARAM}" MATCHES "\\*|&")
if("${PARAM}" MATCHES "^char")
@ -668,13 +669,12 @@ foreach(LINE IN LISTS SOURCE_LINES)
unset(API_SELECTED)
if("${FUNCTYPE}" STREQUAL "${CLS}" AND NOT FUNCNAME)
set(CLS_PARAM_1 ${LEN})
set(CLS_PARAM_2 "${TYPES}")
set(CLS_TYPES "${TYPES}")
elseif("${FUNCNAME}" MATCHES "^_" AND NOT "${TYPES}" STREQUAL "v")
elseif(IS_STATIC)
list(APPEND STATIC_METHODS "${FUNCNAME}:${LEN}:${TYPES}")
list(APPEND STATIC_METHODS "${FUNCNAME}:${TYPES}")
else()
list(APPEND METHODS "${FUNCNAME}:${LEN}:${TYPES}")
list(APPEND METHODS "${FUNCNAME}:${TYPES}")
endif()
continue()
endif()

View File

@ -19,7 +19,7 @@ endif()
file(READ "${API_FILES}" SCRIPT_API_BINARY_FILES)
foreach(FILE IN LISTS SCRIPT_API_BINARY_FILES)
file(STRINGS "${FILE}" LINES REGEX "^void SQ${APIUC}.*_Register\\(Squirrel \\*engine\\)$")
file(STRINGS "${FILE}" LINES REGEX "^void SQ${APIUC}.*_Register\\(Squirrel &engine\\)$")
if(LINES)
string(REGEX REPLACE ".*api/${APILC}/(.*)" "#include \"\\1\"" FILE "${FILE}")
list(APPEND SQUIRREL_INCLUDES "${FILE}")
@ -28,7 +28,7 @@ foreach(FILE IN LISTS SCRIPT_API_BINARY_FILES)
continue()
endif()
string(REGEX REPLACE "^.*void " " " LINE "${LINE}")
string(REGEX REPLACE "Squirrel \\*" "" LINE "${LINE}")
string(REGEX REPLACE "Squirrel &" "" LINE "${LINE}")
list(APPEND SQUIRREL_REGISTER "${LINE}")
endforeach()
endif()

View File

@ -16,8 +16,11 @@
; - `openttd -I <name>` starts OpenTTD with the given set (case sensitive)
; - adding `graphicsset = <name>` to the misc section of openttd.cfg makes
; OpenTTD start with that graphics set by default
; - there is a command line tool for all platforms called md5sum that can
; create the MD5 checksum you need.
; - `grfid -m` can give the GRF file MD5 checksums that you need
; - The `--md5` output option for `nmlc` can also give the MD5 if you are
; encoding from an nml source
; - Simple file MD5 checksums, eg. using `md5sum` are not correct for grf
; container versions other than 1
; - all files specified in this file are search relatively to the path where
; this file is found, i.e. if the graphics files are in a subdir you have
; to add that subdir to the names in this file to! It will NOT search for
@ -44,6 +47,8 @@ description.en_US = howdie
palette = DOS
; preferred blitter, optional; either 8bpp (default) or 32bpp.
blitter = 8bpp
; url, optional
url = https://github.com/my/baseset
; The files section lists the files that replace sprites.
; The file names are case sensitive.

View File

@ -2,8 +2,8 @@
## Table of contents
- 1.0) About
- 2.0) Known bugs
- 1.0) [About](#10-about)
- 2.0) [Known bugs](#20-known-bugs)
## 1.0) About
@ -12,7 +12,7 @@ that are the same as these. If you do, do not act surprised, because
we WILL flame you!
The current list of known bugs that we intend to fix can be found in our
bug tracking system at https://github.com/OpenTTD/OpenTTD/issues
bug tracking system at [https://github.com/OpenTTD/OpenTTD/issues](https://github.com/OpenTTD/OpenTTD/issues)
Also check the closed bugs when searching for your bug in this system as we
might have fixed the bug in the mean time.

Binary file not shown.

View File

@ -1 +1 @@
019dba4830a64ee4345d3d647633e1da
a4a727b03a7cd07ee0499231f7f233f4

View File

@ -671,9 +671,9 @@
// U+2026: Horizontal Ellipsis
-1 * 18 12 04 00 01 26 20 01 01 26 20 02 01 26 20 03 01 26 20
-1 sprites/chars.png 8bpp 560 370 11 12 0 -1 normal
-1 sprites/chars.png 8bpp 560 370 9 12 0 -1 normal
-1 sprites/chars.png 8bpp 560 390 5 7 0 0 normal
-1 sprites/chars.png 8bpp 560 400 15 21 0 -2 normal
-1 sprites/chars.png 8bpp 560 400 14 21 0 -2 normal
-1 sprites/mono.png 8bpp 265 270 7 13 0 0 normal
// U+2039: Single Left-Pointing Angle Quotation Mark
@ -840,3 +840,7 @@
-1 sprites/chars.png 8bpp 630 400 6 21 0 -2 normal
-1 sprites/mono.png 8bpp 325 270 7 13 0 0 normal
-1 sprites/mono.png 8bpp 340 270 7 13 0 0 normal
// U+E29D: Small left arrow
-1 * 6 12 01 01 01 9D E2
-1 sprites/chars.png 8bpp 10 430 5 5 0 1 normal

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -4,7 +4,7 @@
// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
//
-1 * 0 0C "OpenTTD GUI graphics"
-1 * 3 05 15 \b 191 // OPENTTD_SPRITE_COUNT
-1 * 3 05 15 \b 192 // OPENTTD_SPRITE_COUNT
-1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal
-1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal
-1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal
@ -196,3 +196,4 @@
-1 sprites/openttdgui.png 8bpp 567 440 12 10 0 0 normal
-1 sprites/openttdgui.png 8bpp 581 440 10 10 0 0 normal
-1 sprites/openttdgui.png 8bpp 593 440 10 10 0 0 normal
-1 sprites/openttdgui.png 8bpp 605 440 8 10 0 0 normal

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -24,7 +24,7 @@ if (!$Env:AZURE_CODESIGN_ENDPOINT -or !$Env:AZURE_CODESIGN_ACCOUNT_NAME -or !$En
exit
}
Install-Module -Name AzureCodeSigning -Scope CurrentUser -RequiredVersion 0.3.0 -Force -Repository PSGallery
Install-Module -Name TrustedSigning -Scope CurrentUser -RequiredVersion 0.5.3 -Force -Repository PSGallery
$params = @{}
@ -37,4 +37,4 @@ $params["FileDigest"] = "SHA256"
$params["TimestampRfc3161"] = "http://timestamp.acs.microsoft.com"
$params["TimestampDigest"] = "SHA256"
Invoke-AzureCodeSigning @params
Invoke-TrustedSigning @params

View File

@ -17,6 +17,10 @@ function Regression::TestInit()
print(" IsValid(vehicle.plane_speed): " + AIGameSettings.IsValid("vehicle.plane_speed"));
print(" vehicle.plane_speed: " + AIGameSettings.GetValue("vehicle.plane_speed"));
require("require.nut");
print(" TestEnum.value1: " + ::TestEnum.value1);
print(" test_constant: " + ::test_constant);
print(" TestEnum.value2: " + TestEnum.value2);
print(" test_constant: " + test_constant);
print(" min(6, 3): " + min(6, 3));
print(" min(3, 6): " + min(3, 6));
print(" max(6, 3): " + max(6, 3));
@ -824,6 +828,13 @@ function Regression::List()
print(" []:");
print(" 4000 => " + list[4000]);
print(" clone:");
local list3 = clone list;
print(" Clone ListDump:");
foreach (idx, val in list3) {
print(" " + idx + " => " + val);
}
list.Clear();
print(" IsEmpty(): " + list.IsEmpty());
@ -856,6 +867,12 @@ function Regression::List()
it = list.Next();
print(" " + it + " => " + list.GetValue(it));
}
print(" Clone ListDump:");
foreach (idx, val in list3) {
print(" " + idx + " => " + val);
}
}
function Regression::Map()
@ -1017,6 +1034,28 @@ function Regression::Order()
foreach (idx, val in list) {
print(" " + idx + " => " + val);
}
list = AIVehicleList_Station(3, AIVehicle.VT_ROAD);
print(" Count(): " + list.Count());
list.Valuate(AIVehicle.GetLocation);
print(" Location ListDump:");
for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
print(" " + i + " => " + list.GetValue(i));
}
print(" foreach():");
foreach (idx, val in list) {
print(" " + idx + " => " + val);
}
list = AIVehicleList_Station(3, AIVehicle.VT_RAIL);
print(" Count(): " + list.Count());
list.Valuate(AIVehicle.GetLocation);
print(" Location ListDump:");
for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
print(" " + i + " => " + list.GetValue(i));
}
print(" foreach():");
foreach (idx, val in list) {
print(" " + idx + " => " + val);
}
}
function Regression::RailTypeList()
@ -1675,13 +1714,22 @@ function Regression::TownList()
}
print(" HasStatue(): " + AITown.HasStatue(list.Begin()));
print(" GetRoadReworkDuration(): " + AITown.GetRoadReworkDuration(list.Begin()));
print(" GetExclusiveRightsCompany(): " + AITown.GetExclusiveRightsCompany(list.Begin()));
print(" GetExclusiveRightsDuration(): " + AITown.GetExclusiveRightsDuration(list.Begin()));
print(" IsActionAvailable(BUILD_STATUE): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE));
print(" PerformTownAction(BUILD_STATUE): " + AITown.PerformTownAction(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE));
print(" IsActionAvailable(BUILD_STATUE): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE));
print(" HasStatue(): " + AITown.HasStatue(list.Begin()));
print(" GetRoadReworkDuration(): " + AITown.GetRoadReworkDuration(list.Begin()));
print(" IsActionAvailable(ROAD_REBUILD): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_ROAD_REBUILD));
print(" PerformTownAction(ROAD_REBUILD): " + AITown.PerformTownAction(list.Begin(), AITown.TOWN_ACTION_ROAD_REBUILD));
print(" IsActionAvailable(ROAD_REBUILD): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_ROAD_REBUILD));
print(" GetRoadReworkDuration(): " + AITown.GetRoadReworkDuration(list.Begin()));
print(" GetExclusiveRightsCompany(): " + AITown.GetExclusiveRightsCompany(list.Begin()));
print(" GetExclusiveRightsDuration(): " + AITown.GetExclusiveRightsDuration(list.Begin()));
print(" IsActionAvailable(BUY_RIGHTS): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUY_RIGHTS));
print(" PerformTownAction(BUY_RIGHTS): " + AITown.PerformTownAction(list.Begin(), AITown.TOWN_ACTION_BUY_RIGHTS));
print(" IsActionAvailable(BUY_RIGHTS): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUY_RIGHTS));
print(" GetExclusiveRightsCompany(): " + AITown.GetExclusiveRightsCompany(list.Begin()));
print(" GetExclusiveRightsDuration(): " + AITown.GetExclusiveRightsDuration(list.Begin()));
}
function Regression::Tunnel()
@ -1975,6 +2023,33 @@ function Regression::Math()
print(" 13725 > -2147483648: " + ( 13725 > -2147483648));
}
function Regression::PriorityQueue()
{
print("");
print("--PriorityQueue--");
local queue = AIPriorityQueue();
print(" IsEmpty(): " + queue.IsEmpty());
print(" Count(): " + queue.Count());
print(" --Insert--")
for (local i = 0; i < 10; i++) {
print(" Insert(" + i + ", " + i + "): " + queue.Insert(i, i));
}
print(" Exists(5): " + queue.Exists(5));
print(" Insert(5, 5): "+ queue.Insert(5, 5));
print(" IsEmpty(): " + queue.IsEmpty());
print(" Count(): " + queue.Count());
local item = queue.Peek();
print(" Peek(): " + item);
print(" Count(): " + queue.Count());
local item2 = queue.Pop();
print(" Pop(): " + item2);
print(" Count(): " + queue.Count());
print(" " + item + " == " + item2 + " : " + (item == item2));
print(" Clear(): " + queue.Clear());
print(" IsEmpty(): " + queue.IsEmpty());
print(" Count(): " + queue.Count());
}
function Regression::Start()
{
this.TestInit();
@ -2049,6 +2124,20 @@ function Regression::Start()
print(" PresidentName: " + c.GetNewName());
} break;
case AIEvent.ET_EXCLUSIVE_TRANSPORT_RIGHTS: {
local c = AIEventExclusiveTransportRights.Convert(e);
print(" EventName: ExclusiveTransportRights");
print(" CompanyID: " + c.GetCompanyID());
print(" TownID: " + c.GetTownID());
} break;
case AIEvent.ET_ROAD_RECONSTRUCTION: {
local c = AIEventRoadReconstruction.Convert(e);
print(" EventName: RoadReconstruction");
print(" CompanyID: " + c.GetCompanyID());
print(" TownID: " + c.GetTownID());
} break;
default:
print(" Unknown Event");
break;
@ -2057,12 +2146,18 @@ function Regression::Start()
print(" IsEventWaiting: false");
this.Math();
this.PriorityQueue();
/* Check Valuate() is actually limited, MUST BE THE LAST TEST. */
print("--Valuate() with excessive CPU usage--")
local list = AIList();
list.AddItem(0, 0);
local Infinite = function(id) { while(true); }
try {
list = AIIndustryList(Infinite);
} catch (e) {
print("constructor failed with: " + e);
}
list.Valuate(Infinite);
}

View File

@ -1,2 +1,9 @@
print(" Required this file");
const test_constant = 1;
enum TestEnum {
value0,
value1,
value2
};

View File

@ -8,6 +8,10 @@
IsValid(vehicle.plane_speed): true
vehicle.plane_speed: 2
Required this file
TestEnum.value1: 1
test_constant: 1
TestEnum.value2: 2
test_constant: 1
min(6, 3): 3
min(3, 6): 3
max(6, 3): 6
@ -81,7 +85,7 @@
20
30
40
Ops: 8673
Ops: 8649
--Std--
abs(-21): 21
@ -571,6 +575,13 @@
4006 => 12
[]:
4000 => 50
clone:
Clone ListDump:
1005 => 1005
4000 => 50
4001 => 8002
4002 => 8004
4006 => 12
IsEmpty(): true
0 => 5 (true)
ERROR: Next() is invalid as Begin() is never called
@ -580,6 +591,12 @@ ERROR: IsEnd() is invalid as Begin() is never called
2 => 6 (true)
3 => 6 (true)
9 => 0 (false)
Clone ListDump:
1005 => 1005
4000 => 50
4001 => 8002
4002 => 8004
4006 => 12
--Company--
SetName(): true
@ -9423,13 +9440,22 @@ ERROR: IsEnd() is invalid as Begin() is never called
23 => 652
25 => 563
HasStatue(): false
GetRoadReworkDuration(): 0
GetExclusiveRightsCompany(): -1
GetExclusiveRightsDuration(): 0
IsActionAvailable(BUILD_STATUE): true
PerformTownAction(BUILD_STATUE): true
IsActionAvailable(BUILD_STATUE): false
HasStatue(): true
GetRoadReworkDuration(): 0
IsActionAvailable(ROAD_REBUILD): true
PerformTownAction(ROAD_REBUILD): true
IsActionAvailable(ROAD_REBUILD): true
GetRoadReworkDuration(): 6
GetExclusiveRightsCompany(): -1
GetExclusiveRightsDuration(): 0
IsActionAvailable(BUY_RIGHTS): true
PerformTownAction(BUY_RIGHTS): true
IsActionAvailable(BUY_RIGHTS): false
GetExclusiveRightsCompany(): 1
GetExclusiveRightsDuration(): 12
--Tunnel--
IsTunnelTile(): false
@ -9694,6 +9720,14 @@ ERROR: IsEnd() is invalid as Begin() is never called
GetStopLocation(): 1
--VehicleList_Station--
Count(): 1
Location ListDump:
20 => 23596
foreach():
20 => 23596
Count(): 0
Location ListDump:
foreach():
Count(): 1
Location ListDump:
20 => 23596
@ -9726,6 +9760,16 @@ ERROR: IsEnd() is invalid as Begin() is never called
EventName: CompanyRenamed
CompanyID: 1
CompanyName: Little Frutford Transport
GetNextEvent: instance
GetEventType: 28
EventName: RoadReconstruction
CompanyID: 1
TownID: 12
GetNextEvent: instance
GetEventType: 27
EventName: ExclusiveTransportRights
CompanyID: 1
TownID: 12
IsEventWaiting: false
--Math--
@ -9760,21 +9804,38 @@ ERROR: IsEnd() is invalid as Begin() is never called
-1 > 2147483647: false
-2147483648 > 2147483647: false
13725 > -2147483648: true
--PriorityQueue--
IsEmpty(): true
Count(): 0
--Insert--
Insert(0, 0): true
Insert(1, 1): true
Insert(2, 2): true
Insert(3, 3): true
Insert(4, 4): true
Insert(5, 5): true
Insert(6, 6): true
Insert(7, 7): true
Insert(8, 8): true
Insert(9, 9): true
Exists(5): true
Insert(5, 5): true
IsEmpty(): false
Count(): 11
Peek(): 0
Count(): 11
Pop(): 0
Count(): 10
0 == 0 : true
Clear(): (null : 0x00000000)
IsEmpty(): true
Count(): 0
--Valuate() with excessive CPU usage--
constructor failed with: excessive CPU usage in list filter function
Your script made an error: excessive CPU usage in valuator function
*FUNCTION [unknown()] regression/main.nut line [2065]
*FUNCTION [Valuate()] NATIVE line [-1]
*FUNCTION [Start()] regression/main.nut line [2066]
[id] 0
[this] TABLE
[Infinite] CLOSURE
[list] INSTANCE
[this] INSTANCE
Your script made an error: excessive CPU usage in valuator function
*FUNCTION [Start()] regression/main.nut line [2066]
*FUNCTION [Start()] regression/main.nut line [2161]
[Infinite] CLOSURE
[list] INSTANCE

View File

@ -19,6 +19,7 @@
#include <unicode/utypes.h>
#include <unicode/uobject.h>
#include <unicode/uscript.h>
#include <array>
U_NAMESPACE_BEGIN

View File

@ -281,7 +281,7 @@ void Md5::Append(const void *data, const size_t nbytes)
if (offset) {
size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
memcpy(this->buf + offset, p, copy);
std::copy_n(p, copy, this->buf + offset);
if (offset + copy < 64) return;
@ -294,7 +294,7 @@ void Md5::Append(const void *data, const size_t nbytes)
for (; left >= 64; p += 64, left -= 64) this->Process(p);
/* Process a final partial block. */
if (left) memcpy(this->buf, p, left);
if (left) std::copy_n(p, left, this->buf);
}
void Md5::Finish(MD5Hash &digest)

View File

@ -1,6 +1,5 @@
add_files(
sqstdaux.h
sqstdmath.h
sqstdstring.h
squirrel.h
)

View File

@ -1,23 +0,0 @@
/* see copyright notice in squirrel.h */
#ifndef _SQSTD_STRING_H_
#define _SQSTD_STRING_H_
typedef unsigned int SQRexBool;
typedef struct SQRex SQRex;
typedef struct {
const SQChar *begin;
SQInteger len;
} SQRexMatch;
SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error);
void sqstd_rex_free(SQRex *exp);
SQBool sqstd_rex_match(SQRex* exp,const SQChar* text);
SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end);
SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end);
SQInteger sqstd_rex_getsubexpcount(SQRex* exp);
SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp);
SQRESULT sqstd_register_stringlib(HSQUIRRELVM v);
#endif /*_SQSTD_STRING_H_*/

View File

@ -68,7 +68,6 @@ struct SQClass;
struct SQInstance;
struct SQDelegable;
typedef char SQChar;
#define MAX_CHAR 0xFFFF
#define SQUIRREL_VERSION "Squirrel 2.2.5 stable - With custom OpenTTD modifications"
@ -164,17 +163,17 @@ typedef struct tagSQObject
}SQObject;
typedef struct tagSQStackInfos{
const SQChar* funcname;
const SQChar* source;
SQInteger line;
std::string_view funcname;
std::string_view source;
SQInteger line = -1;
}SQStackInfos;
typedef struct SQVM* HSQUIRRELVM;
typedef SQObject HSQOBJECT;
typedef SQInteger (*SQFUNCTION)(HSQUIRRELVM);
typedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size);
typedef void (*SQCOMPILERERROR)(HSQUIRRELVM,const SQChar * /*desc*/,const SQChar * /*source*/,SQInteger /*line*/,SQInteger /*column*/);
typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const std::string &);
typedef void (*SQCOMPILERERROR)(HSQUIRRELVM,std::string_view /*desc*/,std::string_view /*source*/,SQInteger /*line*/,SQInteger /*column*/);
typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,std::string_view);
typedef SQInteger (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,SQInteger);
typedef SQInteger (*SQREADFUNC)(SQUserPointer,SQUserPointer,SQInteger);
@ -182,16 +181,16 @@ typedef SQInteger (*SQREADFUNC)(SQUserPointer,SQUserPointer,SQInteger);
typedef char32_t (*SQLEXREADFUNC)(SQUserPointer);
typedef struct tagSQRegFunction{
const SQChar *name;
std::string_view name;
SQFUNCTION f;
SQInteger nparamscheck;
const SQChar *typemask;
std::optional<std::string_view> typemask;
}SQRegFunction;
typedef struct tagSQFunctionInfo {
SQUserPointer funcid;
const SQChar *name;
const SQChar *source;
std::string_view name;
std::string_view source;
}SQFunctionInfo;
@ -213,8 +212,8 @@ SQInteger sq_getvmstate(HSQUIRRELVM v);
void sq_decreaseops(HSQUIRRELVM v, int amount);
/*compiler*/
SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror);
SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror);
SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,std::string_view sourcename,SQBool raiseerror);
SQRESULT sq_compilebuffer(HSQUIRRELVM v,std::string_view buffer,std::string_view sourcename,SQBool raiseerror);
void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable);
void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable);
void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f);
@ -235,10 +234,9 @@ SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size);
void sq_newtable(HSQUIRRELVM v);
void sq_newarray(HSQUIRRELVM v,SQInteger size);
void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars);
SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask);
SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,std::optional<std::string_view> typemask);
SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx);
void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len);
inline void sq_pushstring(HSQUIRRELVM v, const std::string &str, SQInteger len = -1) { sq_pushstring(v, str.data(), len == -1 ? str.size() : len); }
void sq_pushstring(HSQUIRRELVM v, std::string_view str);
void sq_pushfloat(HSQUIRRELVM v,SQFloat f);
void sq_pushinteger(HSQUIRRELVM v,SQInteger n);
void sq_pushbool(HSQUIRRELVM v,SQBool b);
@ -250,7 +248,7 @@ SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx);
SQBool sq_instanceof(HSQUIRRELVM v);
void sq_tostring(HSQUIRRELVM v,SQInteger idx);
void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b);
SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c);
SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,std::string_view &str);
SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i);
SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f);
SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b);
@ -260,10 +258,10 @@ SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPoint
SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag);
SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag);
void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook);
SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize);
std::span<char> sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize);
SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger idx,SQFunctionInfo *fi);
SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars);
SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name);
SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,std::string_view name);
SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p);
SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag);
SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize);
@ -305,10 +303,9 @@ SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx);
/*calls*/
SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror, int suspend = -1);
SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror);
const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx);
const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err, SQInteger len = -1);
inline SQRESULT sq_throwerror(HSQUIRRELVM v, const std::string_view err) { return sq_throwerror(v, err.data(), err.size()); }
std::optional<std::string_view> sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx);
std::optional<std::string_view> sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval);
SQRESULT sq_throwerror(HSQUIRRELVM v,std::string_view err);
void sq_reseterror(HSQUIRRELVM v);
void sq_getlasterror(HSQUIRRELVM v);
@ -318,7 +315,7 @@ void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj);
void sq_addref(HSQUIRRELVM v,HSQOBJECT *po);
SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po);
void sq_resetobject(HSQOBJECT *po);
const SQChar *sq_objtostring(HSQOBJECT *o);
std::optional<std::string_view> sq_objtostring(HSQOBJECT *o);
SQBool sq_objtobool(HSQOBJECT *o);
SQInteger sq_objtointeger(HSQOBJECT *o);
SQFloat sq_objtofloat(HSQOBJECT *o);
@ -363,7 +360,7 @@ void sq_setdebughook(HSQUIRRELVM v);
/* Limit the total number of ops that can be consumed by an operation */
struct SQOpsLimiter {
SQOpsLimiter(HSQUIRRELVM v, SQInteger ops, const char *label);
SQOpsLimiter(HSQUIRRELVM v, SQInteger ops, std::string_view label);
~SQOpsLimiter();
private:
HSQUIRRELVM _v;

View File

@ -16,28 +16,22 @@ void sqstd_printcallstack(HSQUIRRELVM v)
SQInteger i;
SQBool b;
SQFloat f;
const SQChar *s;
SQInteger level=1; //1 is to skip this function that is level 0
const SQChar *name=nullptr;
SQInteger seq=0;
pf(v,"\nCALLSTACK\n");
while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si)))
{
const SQChar *fn="unknown";
const SQChar *src="unknown";
if(si.funcname)fn=si.funcname;
if(si.source) {
std::string_view fn="unknown";
std::string_view src="unknown";
if(!si.funcname.empty())fn=si.funcname;
if(!si.source.empty()) {
/* We don't want to bother users with absolute paths to all AI files.
* Since the path only reaches NoAI code in a formatted string we have
* to strip it here. Let's hope nobody installs openttd in a subdirectory
* of a directory named /ai/. */
src = strstr(si.source, "\\ai\\");
if (!src) src = strstr(si.source, "/ai/");
if (src) {
src += 4;
} else {
src = si.source;
}
auto p = si.source.find("\\ai\\");
if (p == std::string_view::npos) p = si.source.find("/ai/");
src = (p == std::string_view::npos) ? si.source : si.source.substr(p + 4);
}
pf(v,fmt::format("*FUNCTION [{}()] {} line [{}]\n",fn,src,si.line));
level++;
@ -47,8 +41,9 @@ void sqstd_printcallstack(HSQUIRRELVM v)
for(level=0;level<10;level++){
seq=0;
while((name = sq_getlocal(v,level,seq)))
{
std::optional<std::string_view> opt;
while ((opt = sq_getlocal(v,level,seq)).has_value()) {
std::string_view name = *opt;
seq++;
switch(sq_gettype(v,-1))
{
@ -66,10 +61,12 @@ void sqstd_printcallstack(HSQUIRRELVM v)
case OT_USERPOINTER:
pf(v,fmt::format("[{}] USERPOINTER\n",name));
break;
case OT_STRING:
sq_getstring(v,-1,&s);
pf(v,fmt::format("[{}] \"{}\"\n",name,s));
case OT_STRING: {
std::string_view view;
sq_getstring(v,-1,view);
pf(v,fmt::format("[{}] \"{}\"\n",name,view));
break;
}
case OT_TABLE:
pf(v,fmt::format("[{}] TABLE\n",name));
break;
@ -117,10 +114,10 @@ static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v)
{
SQPRINTFUNCTION pf = sq_getprintfunc(v);
if(pf) {
const SQChar *sErr = nullptr;
std::string_view error;
if(sq_gettop(v)>=1) {
if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr))) {
pf(v,fmt::format("\nAN ERROR HAS OCCURRED [{}]\n",sErr));
if(SQ_SUCCEEDED(sq_getstring(v,2,error))) {
pf(v,fmt::format("\nAN ERROR HAS OCCURRED [{}]\n",error));
}
else{
pf(v,"\nAN ERROR HAS OCCURRED [unknown]\n");
@ -131,7 +128,7 @@ static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v)
return 0;
}
void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSource,SQInteger line,SQInteger column)
void _sqstd_compiler_error(HSQUIRRELVM v,std::string_view sErr,std::string_view sSource,SQInteger line,SQInteger column)
{
SQPRINTFUNCTION pf = sq_getprintfunc(v);
if(pf) {

View File

@ -67,7 +67,7 @@ SINGLE_ARG_FUNC(ceil, 1)
SINGLE_ARG_FUNC(exp, 100)
#define _DECL_FUNC(name,nparams,tycheck) {#name,math_##name,nparams,tycheck}
static SQRegFunction mathlib_funcs[] = {
static const std::initializer_list<SQRegFunction> mathlib_funcs = {
_DECL_FUNC(sqrt,2,".n"),
_DECL_FUNC(sin,2,".n"),
_DECL_FUNC(cos,2,".n"),
@ -84,11 +84,10 @@ static SQRegFunction mathlib_funcs[] = {
_DECL_FUNC(exp,2,".n"),
#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS
_DECL_FUNC(srand,2,".n"),
_DECL_FUNC(rand,1,nullptr),
_DECL_FUNC(rand,1,std::nullopt),
#endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */
_DECL_FUNC(fabs,2,".n"),
_DECL_FUNC(abs,2,".n"),
{nullptr,nullptr,0,nullptr},
};
#ifndef M_PI
@ -97,21 +96,19 @@ static SQRegFunction mathlib_funcs[] = {
SQRESULT sqstd_register_mathlib(HSQUIRRELVM v)
{
SQInteger i=0;
while(mathlib_funcs[i].name!=nullptr) {
sq_pushstring(v,mathlib_funcs[i].name,-1);
sq_newclosure(v,mathlib_funcs[i].f,0);
sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask);
sq_setnativeclosurename(v,-1,mathlib_funcs[i].name);
for(auto &func : mathlib_funcs) {
sq_pushstring(v,func.name);
sq_newclosure(v,func.f,0);
sq_setparamscheck(v,func.nparamscheck,func.typemask);
sq_setnativeclosurename(v,-1,func.name);
sq_createslot(v,-3);
i++;
}
#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS
sq_pushstring(v,"RAND_MAX",-1);
sq_pushstring(v,"RAND_MAX");
sq_pushinteger(v,RAND_MAX);
sq_createslot(v,-3);
#endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */
sq_pushstring(v,"PI",-1);
sq_pushstring(v,"PI");
sq_pushfloat(v,(SQFloat)M_PI);
sq_createslot(v,-3);
return SQ_OK;

View File

@ -1,632 +0,0 @@
/* see copyright notice in squirrel.h */
#include <squirrel.h>
#include <exception>
#include "sqstdstring.h"
#ifdef _UNICODE
#define scisprint iswprint
#else
#define scisprint isprint
#endif
#ifdef _DEBUG
static const SQChar *g_nnames[] =
{
"NONE","OP_GREEDY", "OP_OR",
"OP_EXPR","OP_NOCAPEXPR","OP_DOT", "OP_CLASS",
"OP_CCLASS","OP_NCLASS","OP_RANGE","OP_CHAR",
"OP_EOL","OP_BOL","OP_WB"
};
#endif
#define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
#define OP_OR (MAX_CHAR+2)
#define OP_EXPR (MAX_CHAR+3) //parentesis ()
#define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
#define OP_DOT (MAX_CHAR+5)
#define OP_CLASS (MAX_CHAR+6)
#define OP_CCLASS (MAX_CHAR+7)
#define OP_NCLASS (MAX_CHAR+8) //negates class the [^
#define OP_RANGE (MAX_CHAR+9)
#define OP_CHAR (MAX_CHAR+10)
#define OP_EOL (MAX_CHAR+11)
#define OP_BOL (MAX_CHAR+12)
#define OP_WB (MAX_CHAR+13)
#define SQREX_SYMBOL_ANY_CHAR ('.')
#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
#define SQREX_SYMBOL_BRANCH ('|')
#define SQREX_SYMBOL_END_OF_STRING ('$')
#define SQREX_SYMBOL_BEGINNING_OF_STRING ('^')
#define SQREX_SYMBOL_ESCAPE_CHAR ('\\')
typedef int SQRexNodeType;
typedef struct tagSQRexNode{
SQRexNodeType type;
SQInteger left;
SQInteger right;
SQInteger next;
}SQRexNode;
struct SQRex{
const SQChar *_eol;
const SQChar *_bol;
const SQChar *_p;
SQInteger _first;
SQInteger _op;
SQRexNode *_nodes;
SQInteger _nallocated;
SQInteger _nsize;
SQInteger _nsubexpr;
SQRexMatch *_matches;
SQInteger _currsubexp;
const SQChar **_error;
};
static SQInteger sqstd_rex_list(SQRex *exp);
static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type)
{
SQRexNode n;
n.type = type;
n.next = n.right = n.left = -1;
if(type == OP_EXPR)
n.right = exp->_nsubexpr++;
if(exp->_nallocated < (exp->_nsize + 1)) {
SQInteger oldsize = exp->_nallocated;
exp->_nallocated *= 2;
exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode));
}
exp->_nodes[exp->_nsize++] = n;
SQInteger newid = exp->_nsize - 1;
return (SQInteger)newid;
}
static void sqstd_rex_error(SQRex *exp,const SQChar *error)
{
if(exp->_error) *exp->_error = error;
throw std::exception();
}
static void sqstd_rex_expect(SQRex *exp, SQChar n){
if((*exp->_p) != n)
sqstd_rex_error(exp, "expected paren");
exp->_p++;
}
static SQChar sqstd_rex_escapechar(SQRex *exp)
{
if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){
exp->_p++;
switch(*exp->_p) {
case 'v': exp->_p++; return '\v';
case 'n': exp->_p++; return '\n';
case 't': exp->_p++; return '\t';
case 'r': exp->_p++; return '\r';
case 'f': exp->_p++; return '\f';
default: return (*exp->_p++);
}
} else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,"letter expected");
return (*exp->_p++);
}
static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid)
{
SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS);
exp->_nodes[n].left = classid;
return n;
}
static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass)
{
SQChar t;
if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) {
exp->_p++;
switch(*exp->_p) {
case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n');
case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t');
case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r');
case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f');
case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v');
case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
case 'p': case 'P': case 'l': case 'u':
{
t = *exp->_p; exp->_p++;
return sqstd_rex_charclass(exp,t);
}
case 'b':
case 'B':
if(!isclass) {
SQInteger node = sqstd_rex_newnode(exp,OP_WB);
exp->_nodes[node].left = *exp->_p;
exp->_p++;
return node;
} //else default
default:
t = *exp->_p; exp->_p++;
return sqstd_rex_newnode(exp,t);
}
}
else if(!scisprint(*exp->_p)) {
sqstd_rex_error(exp,"letter expected");
}
t = *exp->_p; exp->_p++;
return sqstd_rex_newnode(exp,t);
}
static SQInteger sqstd_rex_class(SQRex *exp)
{
SQInteger ret = -1;
SQInteger first = -1,chain;
if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){
ret = sqstd_rex_newnode(exp,OP_NCLASS);
exp->_p++;
}else ret = sqstd_rex_newnode(exp,OP_CLASS);
if(*exp->_p == ']') sqstd_rex_error(exp,"empty class");
chain = ret;
while(*exp->_p != ']' && exp->_p != exp->_eol) {
if(*exp->_p == '-' && first != -1){
SQInteger r;
if(*exp->_p++ == ']') sqstd_rex_error(exp,"unfinished range");
r = sqstd_rex_newnode(exp,OP_RANGE);
if(exp->_nodes[first].type>*exp->_p) sqstd_rex_error(exp,"invalid range");
if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,"cannot use character classes in ranges");
exp->_nodes[r].left = exp->_nodes[first].type;
SQInteger t = sqstd_rex_escapechar(exp);
exp->_nodes[r].right = t;
exp->_nodes[chain].next = r;
chain = r;
first = -1;
}
else{
if(first!=-1){
SQInteger c = first;
exp->_nodes[chain].next = c;
chain = c;
first = sqstd_rex_charnode(exp,SQTrue);
}
else{
first = sqstd_rex_charnode(exp,SQTrue);
}
}
}
if(first!=-1){
SQInteger c = first;
exp->_nodes[chain].next = c;
chain = c;
first = -1;
}
/* hack? */
exp->_nodes[ret].left = exp->_nodes[ret].next;
exp->_nodes[ret].next = -1;
return ret;
}
static SQInteger sqstd_rex_parsenumber(SQRex *exp)
{
SQInteger ret = *exp->_p-'0';
SQInteger positions = 10;
exp->_p++;
while(isdigit(*exp->_p)) {
ret = ret*10+(*exp->_p++-'0');
if(positions==1000000000) sqstd_rex_error(exp,"overflow in numeric constant");
positions *= 10;
};
return ret;
}
static SQInteger sqstd_rex_element(SQRex *exp)
{
SQInteger ret = -1;
switch(*exp->_p)
{
case '(': {
SQInteger expr;
exp->_p++;
if(*exp->_p =='?') {
exp->_p++;
sqstd_rex_expect(exp,':');
expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR);
}
else
expr = sqstd_rex_newnode(exp,OP_EXPR);
SQInteger newn = sqstd_rex_list(exp);
exp->_nodes[expr].left = newn;
ret = expr;
sqstd_rex_expect(exp,')');
}
break;
case '[':
exp->_p++;
ret = sqstd_rex_class(exp);
sqstd_rex_expect(exp,']');
break;
case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break;
case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break;
default:
ret = sqstd_rex_charnode(exp,SQFalse);
break;
}
SQInteger op;
SQBool isgreedy = SQFalse;
unsigned short p0 = 0, p1 = 0;
switch(*exp->_p){
case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;
case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break;
case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = SQTrue; break;
case '{':
exp->_p++;
if(!isdigit(*exp->_p)) sqstd_rex_error(exp,"number expected");
p0 = (unsigned short)sqstd_rex_parsenumber(exp);
/*******************************/
switch(*exp->_p) {
case '}':
p1 = p0; exp->_p++;
break;
case ',':
exp->_p++;
p1 = 0xFFFF;
if(isdigit(*exp->_p)){
p1 = (unsigned short)sqstd_rex_parsenumber(exp);
}
sqstd_rex_expect(exp,'}');
break;
default:
sqstd_rex_error(exp,", or } expected");
}
/*******************************/
isgreedy = SQTrue;
break;
}
if(isgreedy) {
SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY);
op = OP_GREEDY;
exp->_nodes[nnode].left = ret;
exp->_nodes[nnode].right = ((p0)<<16)|p1;
ret = nnode;
}
if((*exp->_p != SQREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {
SQInteger nnode = sqstd_rex_element(exp);
exp->_nodes[ret].next = nnode;
}
return ret;
}
static SQInteger sqstd_rex_list(SQRex *exp)
{
SQInteger ret=-1,e;
if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) {
exp->_p++;
ret = sqstd_rex_newnode(exp,OP_BOL);
}
e = sqstd_rex_element(exp);
if(ret != -1) {
exp->_nodes[ret].next = e;
}
else ret = e;
if(*exp->_p == SQREX_SYMBOL_BRANCH) {
SQInteger temp,tright;
exp->_p++;
temp = sqstd_rex_newnode(exp,OP_OR);
exp->_nodes[temp].left = ret;
tright = sqstd_rex_list(exp);
exp->_nodes[temp].right = tright;
ret = temp;
}
return ret;
}
static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c)
{
switch(cclass) {
case 'a': return isalpha(c)?SQTrue:SQFalse;
case 'A': return !isalpha(c)?SQTrue:SQFalse;
case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse;
case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse;
case 's': return isspace(c)?SQTrue:SQFalse;
case 'S': return !isspace(c)?SQTrue:SQFalse;
case 'd': return isdigit(c)?SQTrue:SQFalse;
case 'D': return !isdigit(c)?SQTrue:SQFalse;
case 'x': return isxdigit(c)?SQTrue:SQFalse;
case 'X': return !isxdigit(c)?SQTrue:SQFalse;
case 'c': return iscntrl(c)?SQTrue:SQFalse;
case 'C': return !iscntrl(c)?SQTrue:SQFalse;
case 'p': return ispunct(c)?SQTrue:SQFalse;
case 'P': return !ispunct(c)?SQTrue:SQFalse;
case 'l': return islower(c)?SQTrue:SQFalse;
case 'u': return isupper(c)?SQTrue:SQFalse;
}
return SQFalse; /*cannot happen*/
}
static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQInteger c)
{
do {
switch(node->type) {
case OP_RANGE:
if(c >= node->left && c <= node->right) return SQTrue;
break;
case OP_CCLASS:
if(sqstd_rex_matchcclass(node->left,c)) return SQTrue;
break;
default:
if(c == node->type)return SQTrue;
}
} while((node->next != -1) && (node = &exp->_nodes[node->next]));
return SQFalse;
}
static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next)
{
SQRexNodeType type = node->type;
switch(type) {
case OP_GREEDY: {
//SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : nullptr;
SQRexNode *greedystop = nullptr;
SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
const SQChar *s=str, *good = str;
if(node->next != -1) {
greedystop = &exp->_nodes[node->next];
}
else {
greedystop = next;
}
while((nmaches == 0xFFFF || nmaches < p1)) {
const SQChar *stop;
if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
break;
nmaches++;
good=s;
if(greedystop) {
//checks that 0 matches satisfy the expression(if so skips)
//if not would always stop(for instance if is a '?')
if(greedystop->type != OP_GREEDY ||
(greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
{
SQRexNode *gnext = nullptr;
if(greedystop->next != -1) {
gnext = &exp->_nodes[greedystop->next];
}else if(next && next->next != -1){
gnext = &exp->_nodes[next->next];
}
stop = sqstd_rex_matchnode(exp,greedystop,s,gnext);
if(stop) {
//if satisfied stop it
if(p0 == p1 && p0 == nmaches) break;
else if(nmaches >= p0 && p1 == 0xFFFF) break;
else if(nmaches >= p0 && nmaches <= p1) break;
}
}
}
if(s >= exp->_eol)
break;
}
if(p0 == p1 && p0 == nmaches) return good;
else if(nmaches >= p0 && p1 == 0xFFFF) return good;
else if(nmaches >= p0 && nmaches <= p1) return good;
return nullptr;
}
case OP_OR: {
const SQChar *asd = str;
SQRexNode *temp=&exp->_nodes[node->left];
while( (asd = sqstd_rex_matchnode(exp,temp,asd,nullptr)) ) {
if(temp->next != -1)
temp = &exp->_nodes[temp->next];
else
return asd;
}
asd = str;
temp = &exp->_nodes[node->right];
while( (asd = sqstd_rex_matchnode(exp,temp,asd,nullptr)) ) {
if(temp->next != -1)
temp = &exp->_nodes[temp->next];
else
return asd;
}
return nullptr;
break;
}
case OP_EXPR:
case OP_NOCAPEXPR:{
SQRexNode *n = &exp->_nodes[node->left];
const SQChar *cur = str;
SQInteger capture = -1;
if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
capture = exp->_currsubexp;
exp->_matches[capture].begin = cur;
exp->_currsubexp++;
}
do {
SQRexNode *subnext = nullptr;
if(n->next != -1) {
subnext = &exp->_nodes[n->next];
}else {
subnext = next;
}
if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) {
if(capture != -1){
exp->_matches[capture].begin = 0;
exp->_matches[capture].len = 0;
}
return nullptr;
}
} while((n->next != -1) && (n = &exp->_nodes[n->next]));
if(capture != -1)
exp->_matches[capture].len = cur - exp->_matches[capture].begin;
return cur;
}
case OP_WB:
if((str == exp->_bol && !isspace(*str))
|| (str == exp->_eol && !isspace(*(str-1)))
|| (!isspace(*str) && isspace(*(str+1)))
|| (isspace(*str) && !isspace(*(str+1))) ) {
return (node->left == 'b')?str:nullptr;
}
return (node->left == 'b')?nullptr:str;
case OP_BOL:
if(str == exp->_bol) return str;
return nullptr;
case OP_EOL:
if(str == exp->_eol) return str;
return nullptr;
case OP_DOT:{
*str++;
}
return str;
case OP_NCLASS:
case OP_CLASS:
if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) {
*str++;
return str;
}
return nullptr;
case OP_CCLASS:
if(sqstd_rex_matchcclass(node->left,*str)) {
*str++;
return str;
}
return nullptr;
default: /* char */
if(*str != (SQChar)node->type) return nullptr;
*str++;
return str;
}
return nullptr;
}
/* public api */
SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error)
{
SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex));
exp->_eol = exp->_bol = nullptr;
exp->_p = pattern;
exp->_nallocated = (SQInteger)strlen(pattern) * sizeof(SQChar);
exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode));
exp->_nsize = 0;
exp->_matches = 0;
exp->_nsubexpr = 0;
exp->_first = sqstd_rex_newnode(exp,OP_EXPR);
exp->_error = error;
try {
SQInteger res = sqstd_rex_list(exp);
exp->_nodes[exp->_first].left = res;
if(*exp->_p!='\0')
sqstd_rex_error(exp,"unexpected character");
#ifdef _DEBUG
{
SQInteger nsize,i;
SQRexNode *t;
nsize = exp->_nsize;
t = &exp->_nodes[0];
printf("\n");
/* XXX -- The (int) casts are needed to silent warnings on 64bit systems (SQInteger is 64bit, %d assumes 32bit, (int) is 32bit) */
for(i = 0;i < nsize; i++) {
if(exp->_nodes[i].type>MAX_CHAR)
printf("[%02d] %10s ",(int)i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
else
printf("[%02d] %10c ",(int)i,exp->_nodes[i].type);
printf("left %02d right %02d next %02d\n",(int)exp->_nodes[i].left,(int)exp->_nodes[i].right,(int)exp->_nodes[i].next);
}
printf("\n");
}
#endif
exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch));
memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch));
}
catch (...) {
sqstd_rex_free(exp);
return nullptr;
}
return exp;
}
void sqstd_rex_free(SQRex *exp)
{
if(exp) {
if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode));
if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch));
sq_free(exp,sizeof(SQRex));
}
}
SQBool sqstd_rex_match(SQRex* exp,const SQChar* text)
{
const SQChar* res = nullptr;
exp->_bol = text;
exp->_eol = text + strlen(text);
exp->_currsubexp = 0;
res = sqstd_rex_matchnode(exp,exp->_nodes,text,nullptr);
if(res == nullptr || res != exp->_eol)
return SQFalse;
return SQTrue;
}
SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end)
{
const SQChar *cur = nullptr;
SQInteger node = exp->_first;
if(text_begin >= text_end) return SQFalse;
exp->_bol = text_begin;
exp->_eol = text_end;
do {
cur = text_begin;
while(node != -1) {
exp->_currsubexp = 0;
cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,nullptr);
if(!cur)
break;
node = exp->_nodes[node].next;
}
*text_begin++;
} while(cur == nullptr && text_begin != text_end);
if(cur == nullptr)
return SQFalse;
--text_begin;
if(out_begin) *out_begin = text_begin;
if(out_end) *out_end = cur;
return SQTrue;
}
SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end)
{
return sqstd_rex_searchrange(exp,text,text + strlen(text),out_begin,out_end);
}
SQInteger sqstd_rex_getsubexpcount(SQRex* exp)
{
return exp->_nsubexpr;
}
SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp)
{
if( n<0 || n >= exp->_nsubexpr) return SQFalse;
*subexp = exp->_matches[n];
return SQTrue;
}

View File

@ -1,270 +0,0 @@
/* see copyright notice in squirrel.h */
#include <squirrel.h>
#include <sqstdstring.h>
#define scstrchr strchr
#define scatoi atoi
#define scstrtok strtok
#define MAX_FORMAT_LEN 20
#define MAX_WFORMAT_LEN 3
#define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar))
static SQInteger validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, SQInteger n,SQInteger &width)
{
SQChar swidth[MAX_WFORMAT_LEN];
SQInteger wc = 0;
SQInteger start = n;
fmt[0] = '%';
while (scstrchr("-+ #0", src[n])) n++;
while (isdigit(src[n])) {
swidth[wc] = src[n];
n++;
wc++;
if(wc>=MAX_WFORMAT_LEN)
return sq_throwerror(v,"width format too long");
}
swidth[wc] = '\0';
if(wc > 0) {
width = atoi(swidth);
}
else
width = 0;
if (src[n] == '.') {
n++;
wc = 0;
while (isdigit(src[n])) {
swidth[wc] = src[n];
n++;
wc++;
if(wc>=MAX_WFORMAT_LEN)
return sq_throwerror(v,"precision format too long");
}
swidth[wc] = '\0';
if(wc > 0) {
width += atoi(swidth);
}
}
if (n-start > MAX_FORMAT_LEN )
return sq_throwerror(v,"format too long");
memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar));
fmt[(n-start)+2] = '\0';
return n;
}
static void __strip_l(const SQChar *str,const SQChar **start)
{
const SQChar *t = str;
while(((*t) != '\0') && isspace(*t)){ t++; }
*start = t;
}
static void __strip_r(const SQChar *str,SQInteger len,const SQChar **end)
{
if(len == 0) {
*end = str;
return;
}
const SQChar *t = &str[len-1];
while(t != str && isspace(*t)) { t--; }
*end = t+1;
}
static SQInteger _string_strip(HSQUIRRELVM v)
{
const SQChar *str,*start,*end;
sq_getstring(v,2,&str);
SQInteger len = sq_getsize(v,2);
__strip_l(str,&start);
__strip_r(str,len,&end);
sq_pushstring(v,start,end - start);
return 1;
}
static SQInteger _string_lstrip(HSQUIRRELVM v)
{
const SQChar *str,*start;
sq_getstring(v,2,&str);
__strip_l(str,&start);
sq_pushstring(v,start,-1);
return 1;
}
static SQInteger _string_rstrip(HSQUIRRELVM v)
{
const SQChar *str,*end;
sq_getstring(v,2,&str);
SQInteger len = sq_getsize(v,2);
__strip_r(str,len,&end);
sq_pushstring(v,str,end - str);
return 1;
}
static SQInteger _string_split(HSQUIRRELVM v)
{
const SQChar *str,*seps;
SQChar *stemp,*tok;
sq_getstring(v,2,&str);
sq_getstring(v,3,&seps);
if(sq_getsize(v,3) == 0) return sq_throwerror(v,"empty separators string");
SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar);
stemp = sq_getscratchpad(v,memsize);
memcpy(stemp,str,memsize);
tok = scstrtok(stemp,seps);
sq_newarray(v,0);
while( tok != nullptr ) {
sq_pushstring(v,tok,-1);
sq_arrayappend(v,-2);
tok = scstrtok( nullptr, seps );
}
return 1;
}
#define SETUP_REX(v) \
SQRex *self = nullptr; \
sq_getinstanceup(v,1,(SQUserPointer *)&self,0);
static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger size)
{
SQRex *self = ((SQRex *)p);
sqstd_rex_free(self);
return 1;
}
static SQInteger _regexp_match(HSQUIRRELVM v)
{
SETUP_REX(v);
const SQChar *str;
sq_getstring(v,2,&str);
if(sqstd_rex_match(self,str) == SQTrue)
{
sq_pushbool(v,SQTrue);
return 1;
}
sq_pushbool(v,SQFalse);
return 1;
}
static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end)
{
sq_newtable(v);
sq_pushstring(v,"begin",-1);
sq_pushinteger(v,begin - str);
sq_rawset(v,-3);
sq_pushstring(v,"end",-1);
sq_pushinteger(v,end - str);
sq_rawset(v,-3);
}
static SQInteger _regexp_search(HSQUIRRELVM v)
{
SETUP_REX(v);
const SQChar *str,*begin,*end;
SQInteger start = 0;
sq_getstring(v,2,&str);
if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);
if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {
_addrexmatch(v,str,begin,end);
return 1;
}
return 0;
}
static SQInteger _regexp_capture(HSQUIRRELVM v)
{
SETUP_REX(v);
const SQChar *str,*begin,*end;
SQInteger start = 0;
sq_getstring(v,2,&str);
if(sq_gettop(v) > 2) sq_getinteger(v,3,&start);
if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) {
SQInteger n = sqstd_rex_getsubexpcount(self);
SQRexMatch match;
sq_newarray(v,0);
for(SQInteger i = 0;i < n; i++) {
sqstd_rex_getsubexp(self,i,&match);
if(match.len > 0)
_addrexmatch(v,str,match.begin,match.begin+match.len);
else
_addrexmatch(v,str,str,str); //empty match
sq_arrayappend(v,-2);
}
return 1;
}
return 0;
}
static SQInteger _regexp_subexpcount(HSQUIRRELVM v)
{
SETUP_REX(v);
sq_pushinteger(v,sqstd_rex_getsubexpcount(self));
return 1;
}
static SQInteger _regexp_constructor(HSQUIRRELVM v)
{
const SQChar *error,*pattern;
sq_getstring(v,2,&pattern);
SQRex *rex = sqstd_rex_compile(pattern,&error);
if(!rex) return sq_throwerror(v,error);
sq_setinstanceup(v,1,rex);
sq_setreleasehook(v,1,_rexobj_releasehook);
return 0;
}
static SQInteger _regexp__typeof(HSQUIRRELVM v)
{
sq_pushstring(v,"regexp",-1);
return 1;
}
#define _DECL_REX_FUNC(name,nparams,pmask) {#name,_regexp_##name,nparams,pmask}
static SQRegFunction rexobj_funcs[]={
_DECL_REX_FUNC(constructor,2,".s"),
_DECL_REX_FUNC(search,-2,"xsn"),
_DECL_REX_FUNC(match,2,"xs"),
_DECL_REX_FUNC(capture,-2,"xsn"),
_DECL_REX_FUNC(subexpcount,1,"x"),
_DECL_REX_FUNC(_typeof,1,"x"),
{0,0,0,0}
};
#define _DECL_FUNC(name,nparams,pmask) {#name,_string_##name,nparams,pmask}
static SQRegFunction stringlib_funcs[]={
_DECL_FUNC(format,-2,".s"),
_DECL_FUNC(strip,2,".s"),
_DECL_FUNC(lstrip,2,".s"),
_DECL_FUNC(rstrip,2,".s"),
_DECL_FUNC(split,3,".ss"),
{0,0,0,0}
};
SQInteger sqstd_register_stringlib(HSQUIRRELVM v)
{
sq_pushstring(v,"regexp",-1);
sq_newclass(v,SQFalse);
SQInteger i = 0;
while(rexobj_funcs[i].name != 0) {
SQRegFunction &f = rexobj_funcs[i];
sq_pushstring(v,f.name,-1);
sq_newclosure(v,f.f,0);
sq_setparamscheck(v,f.nparamscheck,f.typemask);
sq_setnativeclosurename(v,-1,f.name);
sq_createslot(v,-3);
i++;
}
sq_createslot(v,-3);
i = 0;
while(stringlib_funcs[i].name!=0)
{
sq_pushstring(v,stringlib_funcs[i].name,-1);
sq_newclosure(v,stringlib_funcs[i].f,0);
sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask);
sq_setnativeclosurename(v,-1,stringlib_funcs[i].name);
sq_createslot(v,-3);
i++;
}
return 1;
}

View File

@ -132,7 +132,7 @@ void sq_close(HSQUIRRELVM v)
sq_delete(ss, SQSharedState);
}
SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror)
SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,std::string_view sourcename,SQBool raiseerror)
{
SQObjectPtr o;
if(Compile(v, read, p, sourcename, o, raiseerror != 0, _ss(v)->_debuginfo)) {
@ -173,12 +173,12 @@ SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po)
#endif
}
const SQChar *sq_objtostring(HSQOBJECT *o)
std::optional<std::string_view> sq_objtostring(HSQOBJECT *o)
{
if(sq_type(*o) == OT_STRING) {
return _stringval(*o);
}
return nullptr;
return std::nullopt;
}
SQInteger sq_objtointeger(HSQOBJECT *o)
@ -210,11 +210,9 @@ void sq_pushnull(HSQUIRRELVM v)
v->Push(_null_);
}
void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len)
void sq_pushstring(HSQUIRRELVM v,std::string_view s)
{
if(s)
v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len)));
else v->Push(_null_);
v->Push(SQObjectPtr(SQString::Create(_ss(v), s)));
}
void sq_pushinteger(HSQUIRRELVM v,SQInteger n)
@ -376,7 +374,7 @@ SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparam
return sq_throwerror(v,"the object is not a closure");
}
SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name)
SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,std::string_view name)
{
SQObject o = stack_get(v, idx);
if(sq_isnativeclosure(o)) {
@ -387,16 +385,16 @@ SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name)
return sq_throwerror(v,"the object is not a nativeclosure");
}
SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask)
SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,std::optional<std::string_view> typemask)
{
SQObject o = stack_get(v, -1);
if(!sq_isnativeclosure(o))
return sq_throwerror(v, "native closure expected");
SQNativeClosure *nc = _nativeclosure(o);
nc->_nparamscheck = nparamscheck;
if(typemask) {
if(typemask.has_value()) {
SQIntVec res;
if(!CompileTypemask(res, typemask))
if(!CompileTypemask(res, *typemask))
return sq_throwerror(v, "invalid typemask");
nc->_typecheck.copy(res);
}
@ -553,11 +551,11 @@ SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b)
return SQ_ERROR;
}
SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c)
SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,std::string_view &str)
{
SQObjectPtr *o = nullptr;
_GETSAFE_OBJ(v, idx, OT_STRING,o);
*c = _stringval(*o);
str = _stringval(*o);
return SQ_OK;
}
@ -585,7 +583,7 @@ SQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx)
SQObjectPtr &o = stack_get(v, idx);
SQObjectType type = type(o);
switch(type) {
case OT_STRING: return _string(o)->_len;
case OT_STRING: return _string(o)->View().size();
case OT_TABLE: return _table(o)->CountUsed();
case OT_ARRAY: return _array(o)->Size();
case OT_USERDATA: return _userdata(o)->_size;
@ -897,7 +895,7 @@ SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po)
return SQ_OK;
}
const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx)
std::optional<std::string_view> sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx)
{
SQUnsignedInteger cstksize=v->_callsstacksize;
SQUnsignedInteger lvl=(cstksize-level)-1;
@ -909,7 +907,7 @@ const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedIntege
}
SQVM::CallInfo &ci=v->_callsstack[lvl];
if(type(ci._closure)!=OT_CLOSURE)
return nullptr;
return std::nullopt;
SQClosure *c=_closure(ci._closure);
SQFunctionProto *func=_funcproto(c->_function);
if(func->_noutervalues > (SQInteger)idx) {
@ -919,7 +917,7 @@ const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedIntege
idx -= func->_noutervalues;
return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions)-1);
}
return nullptr;
return std::nullopt;
}
void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj)
@ -932,9 +930,9 @@ void sq_resetobject(HSQOBJECT *po)
po->_unVal.pUserPointer=nullptr;po->_type=OT_NULL;
}
SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err, SQInteger len)
SQRESULT sq_throwerror(HSQUIRRELVM v,std::string_view error)
{
v->_lasterror=SQString::Create(_ss(v),err, len);
v->_lasterror=SQString::Create(_ss(v),error);
return -1;
}
@ -979,6 +977,10 @@ SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror,
if(!v->_suspended) {
v->Pop(params);//pop closure and args
}
if (!v->_can_suspend && v->IsOpsTillSuspendError()) {
v->Raise_Error(fmt::format("excessive CPU usage in {}", v->_ops_till_suspend_error_label));
return SQ_ERROR;
}
if(retval){
v->Push(res); return SQ_OK;
}
@ -1076,7 +1078,7 @@ SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up)
return SQ_OK;
}
SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize)
std::span<char> sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize)
{
return _ss(v)->GetScratchPad(minsize);
}
@ -1090,19 +1092,18 @@ SQInteger sq_collectgarbage(HSQUIRRELVM v)
#endif
}
const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)
std::optional<std::string_view> sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)
{
SQObjectPtr &self = stack_get(v,idx);
const SQChar *name = nullptr;
if(type(self) == OT_CLOSURE) {
if(_closure(self)->_outervalues.size()>nval) {
v->Push(_closure(self)->_outervalues[nval]);
SQFunctionProto *fp = _funcproto(_closure(self)->_function);
SQOuterVar &ov = fp->_outervalues[nval];
name = _stringval(ov._name);
return _stringval(ov._name);
}
}
return name;
return std::nullopt;
}
SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)
@ -1261,8 +1262,8 @@ char32_t buf_lexfeed(SQUserPointer file)
return consumer.AnyBytesLeft() ? consumer.ReadUtf8(-1) : 0;
}
SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) {
StringConsumer consumer(s, size);
SQRESULT sq_compilebuffer(HSQUIRRELVM v,std::string_view buffer,std::string_view sourcename,SQBool raiseerror) {
StringConsumer consumer{buffer};
return sq_compile(v, buf_lexfeed, &consumer, sourcename, raiseerror);
}
@ -1296,7 +1297,7 @@ void sq_free(void *p,SQUnsignedInteger size)
SQ_FREE(p,size);
}
SQOpsLimiter::SQOpsLimiter(HSQUIRRELVM v, SQInteger ops, const char *label) : _v(v)
SQOpsLimiter::SQOpsLimiter(HSQUIRRELVM v, SQInteger ops, std::string_view label) : _v(v)
{
this->_ops = v->_ops_till_suspend_error_threshold;
if (this->_ops == INT64_MIN) {

View File

@ -5,6 +5,7 @@
#include "../../../stdafx.h"
#include "../../fmt/format.h"
#include "../../../core/string_consumer.hpp"
#include "sqpcheader.h"
#include "sqvm.h"
#include "sqstring.h"
@ -17,19 +18,20 @@
#include "../../../safeguards.h"
bool str2num(const SQChar *s,SQObjectPtr &res)
bool str2num(std::string_view s,SQObjectPtr &res)
{
SQChar *end;
if(strstr(s,".")){
SQFloat r = SQFloat(strtod(s,&end));
if(s == end) return false;
if(s.find('.') != std::string_view::npos){
char *end;
std::string str{s};
SQFloat r = SQFloat(strtod(str.c_str(),&end));
if(str.c_str() == end) return false;
res = r;
return true;
}
else{
SQInteger r = SQInteger(strtol(s,&end,10));
if(s == end) return false;
res = r;
auto val = ParseInteger<int64_t>(s);
if (!val.has_value()) return false;
res = *val;
return true;
}
}
@ -101,29 +103,29 @@ static SQInteger base_getstackinfos(HSQUIRRELVM v)
SQInteger level;
SQStackInfos si;
SQInteger seq = 0;
const SQChar *name = nullptr;
sq_getinteger(v, -1, &level);
if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si)))
{
const SQChar *fn = "unknown";
const SQChar *src = "unknown";
std::string_view fn = "unknown";
std::string_view src = "unknown";
if(si.funcname)fn = si.funcname;
if(si.source)src = si.source;
sq_newtable(v);
sq_pushstring(v, "func", -1);
sq_pushstring(v, fn, -1);
sq_pushstring(v, "func");
sq_pushstring(v, fn);
sq_createslot(v, -3);
sq_pushstring(v, "src", -1);
sq_pushstring(v, src, -1);
sq_pushstring(v, "src");
sq_pushstring(v, src);
sq_createslot(v, -3);
sq_pushstring(v, "line", -1);
sq_pushstring(v, "line");
sq_pushinteger(v, si.line);
sq_createslot(v, -3);
sq_pushstring(v, "locals", -1);
sq_pushstring(v, "locals");
sq_newtable(v);
seq=0;
while ((name = sq_getlocal(v, level, seq))) {
sq_pushstring(v, name, -1);
std::optional<std::string_view> name;
while ((name = sq_getlocal(v, level, seq)).has_value()) {
sq_pushstring(v, *name);
sq_push(v, -2);
sq_createslot(v, -4);
sq_pop(v, 1);
@ -169,9 +171,9 @@ static SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,
static SQInteger base_print(HSQUIRRELVM v)
{
const SQChar *str;
std::string_view str;
sq_tostring(v,2);
sq_getstring(v,-1,&str);
sq_getstring(v,-1,str);
if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,str);
return 0;
}
@ -180,14 +182,14 @@ static SQInteger base_print(HSQUIRRELVM v)
static SQInteger base_compilestring(HSQUIRRELVM v)
{
SQInteger nargs=sq_gettop(v);
const SQChar *src=nullptr,*name="unnamedbuffer";
std::string_view src, name="unnamedbuffer";
SQInteger size;
sq_getstring(v,2,&src);
sq_getstring(v,2,src);
size=sq_getsize(v,2);
if(nargs>2){
sq_getstring(v,3,&name);
sq_getstring(v,3,name);
}
if(SQ_SUCCEEDED(sq_compilebuffer(v,src,size,name,SQFalse)))
if(SQ_SUCCEEDED(sq_compilebuffer(v,src.substr(0, size),name,SQFalse)))
return 1;
else
return SQ_ERROR;
@ -232,62 +234,59 @@ static SQInteger base_array(HSQUIRRELVM v)
static SQInteger base_type(HSQUIRRELVM v)
{
SQObjectPtr &o = stack_get(v,2);
v->Push(SQString::Create(_ss(v),GetTypeName(o),-1));
v->Push(SQString::Create(_ss(v),GetTypeName(o)));
return 1;
}
static SQRegFunction base_funcs[]={
static const std::initializer_list<SQRegFunction> base_funcs={
//generic
#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS
{"seterrorhandler",base_seterrorhandler,2, nullptr},
{"setdebughook",base_setdebughook,2, nullptr},
{"enabledebuginfo",base_enabledebuginfo,2, nullptr},
{"seterrorhandler",base_seterrorhandler,2, std::nullopt},
{"setdebughook",base_setdebughook,2, std::nullopt},
{"enabledebuginfo",base_enabledebuginfo,2, std::nullopt},
{"getstackinfos",base_getstackinfos,2, ".n"},
{"getroottable",base_getroottable,1, nullptr},
{"setroottable",base_setroottable,2, nullptr},
{"getconsttable",base_getconsttable,1, nullptr},
{"setconsttable",base_setconsttable,2, nullptr},
{"getroottable",base_getroottable,1, std::nullopt},
{"setroottable",base_setroottable,2, std::nullopt},
{"getconsttable",base_getconsttable,1, std::nullopt},
{"setconsttable",base_setconsttable,2, std::nullopt},
#endif
{"assert",base_assert,2, nullptr},
{"print",base_print,2, nullptr},
{"assert",base_assert,2, std::nullopt},
{"print",base_print,2, std::nullopt},
#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS
{"compilestring",base_compilestring,-2, ".ss"},
{"newthread",base_newthread,2, ".c"},
{"suspend",base_suspend,-1, nullptr},
{"suspend",base_suspend,-1, std::nullopt},
#endif
{"array",base_array,-2, ".n"},
{"type",base_type,2, nullptr},
{"type",base_type,2, std::nullopt},
#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS
{"dummy",base_dummy,0,nullptr},
{"dummy",base_dummy,0,std::nullopt},
#ifndef NO_GARBAGE_COLLECTOR
{"collectgarbage",base_collectgarbage,1, "t"},
#endif
#endif
{nullptr,nullptr,0,nullptr}
};
void sq_base_register(HSQUIRRELVM v)
{
SQInteger i=0;
sq_pushroottable(v);
while(base_funcs[i].name!=nullptr) {
sq_pushstring(v,base_funcs[i].name,-1);
sq_newclosure(v,base_funcs[i].f,0);
sq_setnativeclosurename(v,-1,base_funcs[i].name);
sq_setparamscheck(v,base_funcs[i].nparamscheck,base_funcs[i].typemask);
for(auto &func : base_funcs) {
sq_pushstring(v,func.name);
sq_newclosure(v,func.f,0);
sq_setnativeclosurename(v,-1,func.name);
sq_setparamscheck(v,func.nparamscheck,func.typemask);
sq_createslot(v,-3);
i++;
}
sq_pushstring(v,"_version_",-1);
sq_pushstring(v,SQUIRREL_VERSION,-1);
sq_pushstring(v,"_version_");
sq_pushstring(v,SQUIRREL_VERSION);
sq_createslot(v,-3);
sq_pushstring(v,"_charsize_",-1);
sq_pushinteger(v,sizeof(SQChar));
sq_pushstring(v,"_charsize_");
sq_pushinteger(v,sizeof(char));
sq_createslot(v,-3);
sq_pushstring(v,"_intsize_",-1);
sq_pushstring(v,"_intsize_");
sq_pushinteger(v,sizeof(SQInteger));
sq_createslot(v,-3);
sq_pushstring(v,"_floatsize_",-1);
sq_pushstring(v,"_floatsize_");
sq_pushinteger(v,sizeof(SQFloat));
sq_createslot(v,-3);
sq_pop(v,1);
@ -370,8 +369,8 @@ static SQInteger obj_clear(HSQUIRRELVM v)
static SQInteger number_delegate_tochar(HSQUIRRELVM v)
{
SQObject &o=stack_get(v,1);
SQChar c = (SQChar)tointeger(o);
v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1));
char c = static_cast<char>(tointeger(o));
v->Push(SQString::Create(_ss(v),std::string_view(&c, 1)));
return 1;
}
@ -409,16 +408,15 @@ static SQInteger table_rawget(HSQUIRRELVM v)
}
SQRegFunction SQSharedState::_table_default_delegate_funcz[]={
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_table_default_delegate_funcz={
{"len",default_delegate_len,1, "t"},
{"rawget",table_rawget,2, "t"},
{"rawset",table_rawset,3, "t"},
{"rawdelete",table_rawdelete,2, "t"},
{"rawin",container_rawexists,2, "t"},
{"weakref",obj_delegate_weakref,1, nullptr },
{"weakref",obj_delegate_weakref,1, std::nullopt },
{"tostring",default_delegate_tostring,1, "."},
{"clear",obj_clear,1, "."},
{nullptr,nullptr,0,nullptr}
};
//ARRAY DEFAULT DELEGATE///////////////////////////////////////
@ -611,7 +609,7 @@ static SQInteger array_slice(HSQUIRRELVM v)
}
SQRegFunction SQSharedState::_array_default_delegate_funcz[]={
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_array_default_delegate_funcz={
{"len",default_delegate_len,1, "a"},
{"append",array_append,2, "a"},
{"extend",array_extend,2, "aa"},
@ -624,10 +622,9 @@ SQRegFunction SQSharedState::_array_default_delegate_funcz[]={
{"reverse",array_reverse,1, "a"},
{"sort",array_sort,-1, "ac"},
{"slice",array_slice,-1, "ann"},
{"weakref",obj_delegate_weakref,1, nullptr },
{"weakref",obj_delegate_weakref,1, std::nullopt },
{"tostring",default_delegate_tostring,1, "."},
{"clear",obj_clear,1, "."},
{nullptr,nullptr,0,nullptr}
};
//STRING DEFAULT DELEGATE//////////////////////////
@ -636,25 +633,25 @@ static SQInteger string_slice(HSQUIRRELVM v)
SQInteger sidx,eidx;
SQObjectPtr o;
if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1;
SQInteger slen = _string(o)->_len;
SQInteger slen = _string(o)->View().size();
if(sidx < 0)sidx = slen + sidx;
if(eidx < 0)eidx = slen + eidx;
if(eidx < sidx) return sq_throwerror(v,"wrong indexes");
if(eidx > slen) return sq_throwerror(v,"slice out of range");
v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx));
v->Push(SQString::Create(_ss(v),_stringval(o).substr(sidx,eidx-sidx)));
return 1;
}
static SQInteger string_find(HSQUIRRELVM v)
{
SQInteger top,start_idx=0;
const SQChar *str,*substr,*ret;
if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){
std::string_view str,substr;
if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,str)) && SQ_SUCCEEDED(sq_getstring(v,2,substr))){
if(top>2)sq_getinteger(v,3,&start_idx);
if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){
ret=strstr(&str[start_idx],substr);
if(ret){
sq_pushinteger(v,(SQInteger)(ret-str));
auto ret = str.find(substr, start_idx);
if(ret != std::string_view::npos){
sq_pushinteger(v,static_cast<SQInteger>(ret));
return 1;
}
}
@ -666,11 +663,11 @@ static SQInteger string_find(HSQUIRRELVM v)
#define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \
{ \
SQObject str=stack_get(v,1); \
SQInteger len=_string(str)->_len; \
const SQChar *sThis=_stringval(str); \
SQChar *sNew=(_ss(v)->GetScratchPad(len)); \
for(SQInteger i=0;i<len;i++) sNew[i]=func(sThis[i]); \
v->Push(SQString::Create(_ss(v),sNew,len)); \
std::string_view sThis=_stringval(str); \
size_t len=sThis.size(); \
std::span<char> sNew=(_ss(v)->GetScratchPad(len)); \
for(size_t i=0;i<len;i++) sNew[i]=func(sThis[i]); \
v->Push(SQString::Create(_ss(v),std::string_view(sNew.data(), len))); \
return 1; \
}
@ -678,7 +675,7 @@ static SQInteger string_find(HSQUIRRELVM v)
STRING_TOFUNCZ(tolower)
STRING_TOFUNCZ(toupper)
SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_string_default_delegate_funcz={
{"len",default_delegate_len,1, "s"},
{"tointeger",default_delegate_tointeger,1, "s"},
{"tofloat",default_delegate_tofloat,1, "s"},
@ -687,18 +684,16 @@ SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
{"find",string_find,-2, "s s n "},
{"tolower",string_tolower,1, "s"},
{"toupper",string_toupper,1, "s"},
{"weakref",obj_delegate_weakref,1, nullptr },
{nullptr,nullptr,0,nullptr}
{"weakref",obj_delegate_weakref,1, std::nullopt },
};
//INTEGER DEFAULT DELEGATE//////////////////////////
SQRegFunction SQSharedState::_number_default_delegate_funcz[]={
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_number_default_delegate_funcz={
{"tointeger",default_delegate_tointeger,1, "n|b"},
{"tofloat",default_delegate_tofloat,1, "n|b"},
{"tostring",default_delegate_tostring,1, "."},
{"tochar",number_delegate_tochar,1, "n|b"},
{"weakref",obj_delegate_weakref,1, nullptr },
{nullptr,nullptr,0,nullptr}
{"weakref",obj_delegate_weakref,1, std::nullopt },
};
//CLOSURE DEFAULT DELEGATE//////////////////////////
@ -749,19 +744,19 @@ static SQInteger closure_getinfos(HSQUIRRELVM v) {
_array(params)->Set((SQInteger)n,f->_parameters[n]);
}
if(f->_varparams) {
_array(params)->Set(nparams-1,SQString::Create(_ss(v),"...",-1));
_array(params)->Set(nparams-1,SQString::Create(_ss(v),"..."));
}
res->NewSlot(SQString::Create(_ss(v),"native",-1),false);
res->NewSlot(SQString::Create(_ss(v),"name",-1),f->_name);
res->NewSlot(SQString::Create(_ss(v),"src",-1),f->_sourcename);
res->NewSlot(SQString::Create(_ss(v),"parameters",-1),params);
res->NewSlot(SQString::Create(_ss(v),"varargs",-1),f->_varparams);
res->NewSlot(SQString::Create(_ss(v),"native"),false);
res->NewSlot(SQString::Create(_ss(v),"name"),f->_name);
res->NewSlot(SQString::Create(_ss(v),"src"),f->_sourcename);
res->NewSlot(SQString::Create(_ss(v),"parameters"),params);
res->NewSlot(SQString::Create(_ss(v),"varargs"),f->_varparams);
}
else { //OT_NATIVECLOSURE
SQNativeClosure *nc = _nativeclosure(o);
res->NewSlot(SQString::Create(_ss(v),"native",-1),true);
res->NewSlot(SQString::Create(_ss(v),"name",-1),nc->_name);
res->NewSlot(SQString::Create(_ss(v),"paramscheck",-1),nc->_nparamscheck);
res->NewSlot(SQString::Create(_ss(v),"native"),true);
res->NewSlot(SQString::Create(_ss(v),"name"),nc->_name);
res->NewSlot(SQString::Create(_ss(v),"paramscheck"),nc->_nparamscheck);
SQObjectPtr typecheck;
if(!nc->_typecheck.empty()) {
typecheck =
@ -770,23 +765,22 @@ static SQInteger closure_getinfos(HSQUIRRELVM v) {
_array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]);
}
}
res->NewSlot(SQString::Create(_ss(v),"typecheck",-1),typecheck);
res->NewSlot(SQString::Create(_ss(v),"typecheck"),typecheck);
}
v->Push(res);
return 1;
}
SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_closure_default_delegate_funcz={
{"call",closure_call,-1, "c"},
{"pcall",closure_pcall,-1, "c"},
{"acall",closure_acall,2, "ca"},
{"pacall",closure_pacall,2, "ca"},
{"weakref",obj_delegate_weakref,1, nullptr },
{"weakref",obj_delegate_weakref,1, std::nullopt },
{"tostring",default_delegate_tostring,1, "."},
{"bindenv",closure_bindenv,2, "c x|y|t"},
{"getinfos",closure_getinfos,1, "c"},
{nullptr,nullptr,0,nullptr}
};
//GENERATOR DEFAULT DELEGATE
@ -801,11 +795,10 @@ static SQInteger generator_getstatus(HSQUIRRELVM v)
return 1;
}
SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_generator_default_delegate_funcz={
{"getstatus",generator_getstatus,1, "g"},
{"weakref",obj_delegate_weakref,1, nullptr },
{"weakref",obj_delegate_weakref,1, std::nullopt },
{"tostring",default_delegate_tostring,1, "."},
{nullptr,nullptr,0,nullptr}
};
//THREAD DEFAULT DELEGATE
@ -871,13 +864,13 @@ static SQInteger thread_getstatus(HSQUIRRELVM v)
SQObjectPtr &o = stack_get(v,1);
switch(sq_getvmstate(_thread(o))) {
case SQ_VMSTATE_IDLE:
sq_pushstring(v,"idle",-1);
sq_pushstring(v,"idle");
break;
case SQ_VMSTATE_RUNNING:
sq_pushstring(v,"running",-1);
sq_pushstring(v,"running");
break;
case SQ_VMSTATE_SUSPENDED:
sq_pushstring(v,"suspended",-1);
sq_pushstring(v,"suspended");
break;
default:
return sq_throwerror(v,"internal VM error");
@ -885,13 +878,12 @@ static SQInteger thread_getstatus(HSQUIRRELVM v)
return 1;
}
SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = {
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_thread_default_delegate_funcz = {
{"call", thread_call, -1, "v"},
{"wakeup", thread_wakeup, -1, "v"},
{"getstatus", thread_getstatus, 1, "v"},
{"weakref",obj_delegate_weakref,1, nullptr },
{"weakref",obj_delegate_weakref,1, std::nullopt },
{"tostring",default_delegate_tostring,1, "."},
{nullptr,nullptr,0,nullptr},
};
static SQInteger class_getattributes(HSQUIRRELVM v)
@ -915,14 +907,13 @@ static SQInteger class_instance(HSQUIRRELVM v)
return SQ_ERROR;
}
SQRegFunction SQSharedState::_class_default_delegate_funcz[] = {
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_class_default_delegate_funcz = {
{"getattributes", class_getattributes, 2, "y."},
{"setattributes", class_setattributes, 3, "y.."},
{"rawin",container_rawexists,2, "y"},
{"weakref",obj_delegate_weakref,1, nullptr },
{"weakref",obj_delegate_weakref,1, std::nullopt },
{"tostring",default_delegate_tostring,1, "."},
{"instance",class_instance,1, "y"},
{nullptr,nullptr,0,nullptr}
};
static SQInteger instance_getclass(HSQUIRRELVM v)
@ -932,12 +923,11 @@ static SQInteger instance_getclass(HSQUIRRELVM v)
return SQ_ERROR;
}
SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = {
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_instance_default_delegate_funcz = {
{"getclass", instance_getclass, 1, "x"},
{"rawin",container_rawexists,2, "x"},
{"weakref",obj_delegate_weakref,1, nullptr },
{"weakref",obj_delegate_weakref,1, std::nullopt },
{"tostring",default_delegate_tostring,1, "."},
{nullptr,nullptr,0,nullptr}
};
static SQInteger weakref_ref(HSQUIRRELVM v)
@ -947,11 +937,10 @@ static SQInteger weakref_ref(HSQUIRRELVM v)
return 1;
}
SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = {
/* static */ const std::initializer_list<SQRegFunction> SQSharedState::_weakref_default_delegate_funcz = {
{"ref",weakref_ref,1, "r"},
{"weakref",obj_delegate_weakref,1, nullptr },
{"weakref",obj_delegate_weakref,1, std::nullopt },
{"tostring",default_delegate_tostring,1, "."},
{nullptr,nullptr,0,nullptr}
};

View File

@ -57,16 +57,12 @@ typedef sqvector<ExpState> ExpStateVec;
class SQCompiler
{
public:
SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) : _token(0), _fs(nullptr), _lex(_ss(v), rg, up), _debugline(0), _debugop(0)
SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, std::string_view sourcename, bool raiseerror, bool lineinfo) : _token(0), _fs(nullptr), _lex(_ss(v), rg, up), _debugline(0), _debugop(0)
{
_vm=v;
_sourcename = SQString::Create(_ss(v), sourcename);
_lineinfo = lineinfo;_raiseerror = raiseerror;
}
[[noreturn]] void Error(const std::string &msg)
{
throw CompileException(msg);
}
void Lex(){ _token = _lex.Lex();}
void PushExpState(){ _expstates.push_back(ExpState()); }
bool IsDerefToken(SQInteger tok)
@ -92,7 +88,7 @@ public:
//do nothing
}
else {
const SQChar *etypename;
std::string_view etypename;
if(tok > 255) {
switch(tok)
{
@ -109,21 +105,21 @@ public:
etypename = "FLOAT";
break;
default:
etypename = _lex.Tok2Str(tok);
etypename = _lex.Tok2Str(tok).value_or("<unknown>");
}
Error(fmt::format("expected '{}'", etypename));
throw CompileException(fmt::format("expected '{}'", etypename));
}
Error(fmt::format("expected '{:c}'", tok));
throw CompileException(fmt::format("expected '{:c}'", tok));
}
}
SQObjectPtr ret;
switch(tok)
{
case TK_IDENTIFIER:
ret = _fs->CreateString(_lex._svalue);
ret = _fs->CreateString(_lex.View());
break;
case TK_STRING_LITERAL:
ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
ret = _fs->CreateString(_lex.View());
break;
case TK_INTEGER:
ret = SQObjectPtr(_lex._nvalue);
@ -140,7 +136,7 @@ public:
{
if(_token == ';') { Lex(); return; }
if(!IsEndOfStatement()) {
Error("end of statement expected (; or lf)");
throw CompileException("end of statement expected (; or lf)");
}
}
void MoveIfCurrentTargetIsLocal() {
@ -233,7 +229,7 @@ public:
}
break;}
case TK_BREAK:
if(_fs->_breaktargets.size() <= 0)Error("'break' has to be in a loop block");
if(_fs->_breaktargets.size() <= 0)throw CompileException("'break' has to be in a loop block");
if(_fs->_breaktargets.top() > 0){
_fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
}
@ -243,7 +239,7 @@ public:
Lex();
break;
case TK_CONTINUE:
if(_fs->_continuetargets.size() <= 0)Error("'continue' has to be in a loop block");
if(_fs->_continuetargets.size() <= 0)throw CompileException("'continue' has to be in a loop block");
if(_fs->_continuetargets.top() > 0) {
_fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
}
@ -356,19 +352,19 @@ public:
SQInteger op = _token;
SQInteger ds = _exst._deref;
bool freevar = _exst._freevar;
if(ds == DEREF_NO_DEREF) Error("can't assign expression");
if(ds == DEREF_NO_DEREF) throw CompileException("can't assign expression");
Lex(); Expression();
switch(op){
case TK_NEWSLOT:
if(freevar) Error("free variables cannot be modified");
if(freevar) throw CompileException("free variables cannot be modified");
if(ds == DEREF_FIELD)
EmitDerefOp(_OP_NEWSLOT);
else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
Error("can't 'create' a local slot");
throw CompileException("can't 'create' a local slot");
break;
case '=': //ASSIGN
if(freevar) Error("free variables cannot be modified");
if(freevar) throw CompileException("free variables cannot be modified");
if(ds == DEREF_FIELD)
EmitDerefOp(_OP_SET);
else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
@ -533,7 +529,7 @@ public:
if(_token == TK_PARENT) {
Lex();
if(!NeedGet())
Error("parent cannot be set");
throw CompileException("parent cannot be set");
SQInteger src = _fs->PopTarget();
_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src);
}
@ -546,7 +542,7 @@ public:
}
break;
case '[':
if(_lex._prevtoken == '\n') Error("cannot brake deref/or comma needed after [exp]=exp slot declaration");
if(_lex._prevtoken == '\n') throw CompileException("cannot brake deref/or comma needed after [exp]=exp slot declaration");
Lex(); Expression(); Expect(']');
pos = -1;
if(NeedGet()) Emit2ArgsOP(_OP_GET);
@ -598,7 +594,7 @@ public:
switch(_token)
{
case TK_STRING_LITERAL: {
_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
_fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex.View())));
Lex();
}
break;
@ -618,7 +614,7 @@ public:
SQObject id;
SQObject constant;
switch(_token) {
case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;
case TK_IDENTIFIER: id = _fs->CreateString(_lex.View()); break;
case TK_THIS: id = _fs->CreateString("this"); break;
case TK_CONSTRUCTOR: id = _fs->CreateString("constructor"); break;
}
@ -638,7 +634,7 @@ public:
Expect('.'); constid = Expect(TK_IDENTIFIER);
if(!_table(constant)->Get(constid,constval)) {
constval.Null();
Error(fmt::format("invalid constant [{}.{}]", _stringval(id),_stringval(constid)));
throw CompileException(fmt::format("invalid constant [{}.{}]", _stringval(id),_stringval(constid)));
}
}
else {
@ -742,7 +738,7 @@ public:
case TK_DELEGATE : DelegateExpr(); break;
case '(': Lex(); CommaExpr(); Expect(')');
break;
default: Error("expression expected");
default: throw CompileException("expression expected");
}
return -1;
}
@ -771,7 +767,7 @@ public:
nargs++;
if(_token == ','){
Lex();
if(_token == ')') Error("expression expected, found ')'");
if(_token == ')') throw CompileException("expression expected, found ')'");
}
}
Lex();
@ -1082,13 +1078,13 @@ public:
_exst._funcarg = false;
PrefixedExpr();
es = PopExpState();
if(es._deref == DEREF_NO_DEREF) Error("invalid class name");
if(es._deref == DEREF_NO_DEREF) throw CompileException("invalid class name");
if(es._deref == DEREF_FIELD) {
ClassExp();
EmitDerefOp(_OP_NEWSLOT);
_fs->PopTarget();
}
else Error("cannot create a class in a local with the syntax(class <local>)");
else throw CompileException("cannot create a class in a local with the syntax(class <local>)");
}
SQObject ExpectScalar()
{
@ -1103,7 +1099,7 @@ public:
val._unVal.fFloat = _lex._fvalue;
break;
case TK_STRING_LITERAL:
val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
val = _fs->CreateString(_lex.View());
break;
case '-':
Lex();
@ -1118,12 +1114,12 @@ public:
val._unVal.fFloat = -_lex._fvalue;
break;
default:
Error("scalar expected : integer,float");
throw CompileException("scalar expected : integer,float");
val._type = OT_NULL; // Silent compile-warning
}
break;
default:
Error("scalar expected : integer,float or string");
throw CompileException("scalar expected : integer,float or string");
val._type = OT_NULL; // Silent compile-warning
}
Lex();
@ -1226,9 +1222,9 @@ public:
_exst._funcarg = false;
PrefixedExpr();
es = PopExpState();
if(es._deref == DEREF_NO_DEREF) Error("can't delete an expression");
if(es._deref == DEREF_NO_DEREF) throw CompileException("can't delete an expression");
if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE);
else Error("cannot delete a local");
else throw CompileException("cannot delete a local");
}
void PrefixIncDec(SQInteger token)
{
@ -1255,10 +1251,10 @@ public:
SQInteger defparams = 0;
while(_token!=')') {
if(_token == TK_VARPARAMS) {
if(defparams > 0) Error("function with default parameters cannot have variable number of parameters");
if(defparams > 0) throw CompileException("function with default parameters cannot have variable number of parameters");
funcstate->_varparams = true;
Lex();
if(_token != ')') Error("expected ')'");
if(_token != ')') throw CompileException("expected ')'");
break;
}
else {
@ -1271,10 +1267,10 @@ public:
defparams++;
}
else {
if(defparams > 0) Error("expected '='");
if(defparams > 0) throw CompileException("expected '='");
}
if(_token == ',') Lex();
else if(_token != ')') Error("expected ')' or ','");
else if(_token != ')') throw CompileException("expected ')' or ','");
}
}
Expect(')');
@ -1289,7 +1285,7 @@ public:
//outers are treated as implicit local variables
funcstate->AddOuterValue(paramname);
if(_token == ',') Lex();
else if(_token != ')') Error("expected ')' or ','");
else if(_token != ')') throw CompileException("expected ')' or ','");
}
Lex();
}
@ -1346,7 +1342,7 @@ private:
SQVM *_vm;
};
bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, std::string_view sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
{
SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
return p.Compile(out);

View File

@ -73,5 +73,5 @@ struct SQVM;
using CompileException = std::runtime_error;
bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo);
bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, std::string_view sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo);
#endif //_SQCOMPILER_H_

View File

@ -37,7 +37,7 @@ SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si)
{
SQInteger cssize = v->_callsstacksize;
if (cssize > level) {
memset(si, 0, sizeof(SQStackInfos));
*si = {};
SQVM::CallInfo &ci = v->_callsstack[cssize-level-1];
switch (type(ci._closure)) {
case OT_CLOSURE:{
@ -101,15 +101,15 @@ void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2)
void SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type)
{
SQObjectPtr exptypes = SQString::Create(_ss(this), "", -1);
SQObjectPtr exptypes = SQString::Create(_ss(this), "");
SQInteger found = 0;
for(SQInteger i=0; i<16; i++)
{
SQInteger mask = 0x00000001LL << i;
if(typemask & (mask)) {
if(found>0) StringCat(exptypes,SQString::Create(_ss(this), "|", -1), exptypes);
if(found>0) StringCat(exptypes,SQString::Create(_ss(this), "|"), exptypes);
found ++;
StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes);
StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask)), exptypes);
}
}
Raise_Error(fmt::format("parameter {} has an invalid type '{}' ; expected: '{}'", nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)));

View File

@ -114,7 +114,7 @@ public:
this->~SQFunctionProto();
sq_vm_free(this,size);
}
const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop);
std::optional<std::string_view> GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop);
SQInteger GetLine(SQInstruction *curr);
bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write);
static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret);

View File

@ -110,11 +110,6 @@ SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent)
}
void SQFuncState::Error(const SQChar *err)
{
throw CompileException(err);
}
#ifdef _DEBUG_DUMP
void SQFuncState::Dump(SQFunctionProto *func)
{
@ -234,7 +229,7 @@ SQInteger SQFuncState::GetConstant(const SQObject &cons)
_nliterals++;
if(_nliterals > MAX_LITERALS) {
val.Null();
Error("internal compiler error: too many literals");
throw CompileException("internal compiler error: too many literals");
}
}
return _integer(val);
@ -264,7 +259,7 @@ SQInteger SQFuncState::AllocStackPos()
SQInteger npos=_vlocals.size();
_vlocals.push_back(SQLocalVarInfo());
if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) {
if(_stacksize>MAX_FUNC_STACKSIZE) Error("internal compiler error: too many locals");
if(_stacksize>MAX_FUNC_STACKSIZE) throw CompileException("internal compiler error: too many locals");
_stacksize=_vlocals.size();
}
return npos;
@ -499,9 +494,9 @@ void SQFuncState::AddInstruction(SQInstruction &i)
_instructions.push_back(i);
}
SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len)
SQObject SQFuncState::CreateString(std::string_view s)
{
SQObjectPtr ns(SQString::Create(_sharedstate,s,len));
SQObjectPtr ns(SQString::Create(_sharedstate,s));
_table(_strings)->NewSlot(ns,(SQInteger)1);
return std::move(ns);
}
@ -539,7 +534,7 @@ SQFunctionProto *SQFuncState::BuildProto()
for(SQUnsignedInteger no = 0; no < _lineinfos.size(); no++) f->_lineinfos[no] = _lineinfos[no];
for(SQUnsignedInteger no = 0; no < _defaultparams.size(); no++) f->_defaultparams[no] = _defaultparams[no];
memcpy(f->_instructions,&_instructions[0],(size_t)_instructions.size()*sizeof(SQInstruction));
std::copy_n(&_instructions[0], _instructions.size(), f->_instructions);
f->_varparams = _varparams;

View File

@ -11,7 +11,6 @@ struct SQFuncState
#ifdef _DEBUG_DUMP
void Dump(SQFunctionProto *func);
#endif
[[noreturn]] void Error(const SQChar *err);
SQFuncState *PushChildState(SQSharedState *ss);
void PopChildState();
void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);}
@ -43,7 +42,7 @@ struct SQFuncState
SQInteger TopTarget();
SQInteger GetUpTarget(SQInteger n);
bool IsLocal(SQUnsignedInteger stkpos);
SQObject CreateString(const SQChar *s,SQInteger len = -1);
SQObject CreateString(std::string_view s);
SQObject CreateTable();
bool IsConstant(const SQObject &name,SQObject &e);
SQInteger _returnexp;

View File

@ -12,6 +12,7 @@
#include "sqlexer.h"
#include "../../../core/utf8.hpp"
#include "../../../core/string_consumer.hpp"
#include "../../../safeguards.h"
@ -84,22 +85,16 @@ SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up)
_prevtoken = -1;
_curtoken = -1;
_svalue = nullptr;
_nvalue = 0;
_fvalue = 0;
Next();
}
[[noreturn]] void SQLexer::Error(const SQChar *err)
{
throw CompileException(err);
}
void SQLexer::Next()
{
char32_t t = _readf(_up);
if(t > MAX_CHAR) Error("Invalid character");
if(t > MAX_CHAR) throw CompileException("Invalid character");
if(t != 0) {
_currdata = t;
return;
@ -107,7 +102,7 @@ void SQLexer::Next()
_currdata = SQUIRREL_EOB;
}
const SQChar *SQLexer::Tok2Str(SQInteger tok)
std::optional<std::string_view> SQLexer::Tok2Str(SQInteger tok)
{
SQObjectPtr itr, key, val;
SQInteger nitr;
@ -116,7 +111,7 @@ const SQChar *SQLexer::Tok2Str(SQInteger tok)
if(((SQInteger)_integer(val)) == tok)
return _stringval(key);
}
return nullptr;
return std::nullopt;
}
void SQLexer::LexBlockComment()
@ -126,7 +121,7 @@ void SQLexer::LexBlockComment()
switch(CUR_CHAR) {
case '*': { NEXT(); if(CUR_CHAR == '/') { done = true; NEXT(); }}; continue;
case '\n': _currentline++; NEXT(); continue;
case SQUIRREL_EOB: Error("missing \"*/\" in comment");
case SQUIRREL_EOB: throw CompileException("missing \"*/\" in comment");
default: NEXT();
}
}
@ -195,11 +190,11 @@ SQInteger SQLexer::Lex()
SQInteger stype;
NEXT();
if(CUR_CHAR != '"')
Error("string expected");
throw CompileException("string expected");
if((stype=ReadString('"',true))!=-1) {
RETURN_TOKEN(stype);
}
Error("error parsing the string");
throw CompileException("error parsing the string");
}
case '"':
case '\'': {
@ -207,7 +202,7 @@ SQInteger SQLexer::Lex()
if((stype=ReadString(CUR_CHAR,false))!=-1){
RETURN_TOKEN(stype);
}
Error("error parsing the string");
throw CompileException("error parsing the string");
}
case '{': case '}': case '(': case ')': case '[': case ']':
case ';': case ',': case '?': case '^': case '~':
@ -217,7 +212,7 @@ SQInteger SQLexer::Lex()
NEXT();
if (CUR_CHAR != '.'){ RETURN_TOKEN('.') }
NEXT();
if (CUR_CHAR != '.'){ Error("invalid token '..'"); }
if (CUR_CHAR != '.'){ throw CompileException("invalid token '..'"); }
NEXT();
RETURN_TOKEN(TK_VARPARAMS);
case '&':
@ -263,7 +258,7 @@ SQInteger SQLexer::Lex()
}
else {
SQInteger c = CUR_CHAR;
if (iscntrl((int)c)) Error("unexpected character(control)");
if (iscntrl((int)c)) throw CompileException("unexpected character(control)");
NEXT();
RETURN_TOKEN(c);
}
@ -274,7 +269,7 @@ SQInteger SQLexer::Lex()
return 0;
}
SQInteger SQLexer::GetIDType(SQChar *s)
SQInteger SQLexer::GetIDType(std::string_view s)
{
SQObjectPtr t;
if(_keywords->Get(SQString::Create(_sharedstate, s), t)) {
@ -293,10 +288,10 @@ SQInteger SQLexer::ReadString(char32_t ndelim,bool verbatim)
while(CUR_CHAR != ndelim) {
switch(CUR_CHAR) {
case SQUIRREL_EOB:
Error("unfinished string");
throw CompileException("unfinished string");
return -1;
case '\n':
if(!verbatim) Error("newline in a constant");
if(!verbatim) throw CompileException("newline in a constant");
APPEND_CHAR(CUR_CHAR); NEXT();
_currentline++;
break;
@ -308,18 +303,18 @@ SQInteger SQLexer::ReadString(char32_t ndelim,bool verbatim)
NEXT();
switch(CUR_CHAR) {
case 'x': NEXT(); {
if(!isxdigit(CUR_CHAR)) Error("hexadecimal number expected");
if(!isxdigit(CUR_CHAR)) throw CompileException("hexadecimal number expected");
const SQInteger maxdigits = 4;
SQChar temp[maxdigits+1];
SQInteger n = 0;
char temp[maxdigits];
size_t n = 0;
while(isxdigit(CUR_CHAR) && n < maxdigits) {
temp[n] = CUR_CHAR;
n++;
NEXT();
}
temp[n] = 0;
SQChar *sTemp;
APPEND_CHAR((SQChar)strtoul(temp,&sTemp,16));
auto val = ParseInteger(std::string_view{temp, n}, 16);
if (!val.has_value()) throw CompileException("hexadecimal number expected");
APPEND_CHAR(static_cast<char>(*val));
}
break;
case 't': APPEND_CHAR('\t'); NEXT(); break;
@ -334,7 +329,7 @@ SQInteger SQLexer::ReadString(char32_t ndelim,bool verbatim)
case '"': APPEND_CHAR('"'); NEXT(); break;
case '\'': APPEND_CHAR('\''); NEXT(); break;
default:
Error("unrecognised escaper char");
throw CompileException("unrecognised escaper char");
break;
}
}
@ -353,49 +348,16 @@ SQInteger SQLexer::ReadString(char32_t ndelim,bool verbatim)
break;
}
}
TERMINATE_BUFFER();
SQInteger len = _longstr.size()-1;
if(ndelim == '\'') {
if(len == 0) Error("empty constant");
if(len > 1) Error("constant too long");
if(_longstr.empty()) throw CompileException("empty constant");
if(_longstr.size() > 1) throw CompileException("constant too long");
_nvalue = _longstr[0];
return TK_INTEGER;
}
_svalue = &_longstr[0];
return TK_STRING_LITERAL;
}
void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res)
{
*res = 0;
while(*s != 0)
{
if(isdigit(*s)) *res = (*res)*16+((*s++)-'0');
else if(isxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10);
else { assert(0); }
}
}
void LexInteger(const SQChar *s,SQUnsignedInteger *res)
{
*res = 0;
while(*s != 0)
{
*res = (*res)*10+((*s++)-'0');
}
}
SQInteger scisodigit(SQChar c) { return c >= '0' && c <= '7'; }
void LexOctal(const SQChar *s,SQUnsignedInteger *res)
{
*res = 0;
while(*s != 0)
{
if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0');
else { assert(0); }
}
}
SQInteger scisodigit(char c) { return c >= '0' && c <= '7'; }
SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }
@ -409,7 +371,6 @@ SQInteger SQLexer::ReadNumber()
#define TSCIENTIFIC 4
#define TOCTAL 5
SQInteger type = TINT, firstchar = CUR_CHAR;
SQChar *sTemp;
INIT_TEMP_STRING();
NEXT();
if(firstchar == '0' && (toupper(CUR_CHAR) == 'X' || scisodigit(CUR_CHAR)) ) {
@ -419,7 +380,7 @@ SQInteger SQLexer::ReadNumber()
APPEND_CHAR(CUR_CHAR);
NEXT();
}
if(isdigit(CUR_CHAR)) Error("invalid octal number");
if(isdigit(CUR_CHAR)) throw CompileException("invalid octal number");
}
else {
NEXT();
@ -428,7 +389,7 @@ SQInteger SQLexer::ReadNumber()
APPEND_CHAR(CUR_CHAR);
NEXT();
}
if(_longstr.size() > MAX_HEX_DIGITS) Error("too many digits for an Hex number");
if(_longstr.size() > MAX_HEX_DIGITS) throw CompileException("too many digits for an Hex number");
}
}
else {
@ -436,7 +397,7 @@ SQInteger SQLexer::ReadNumber()
while (CUR_CHAR == '.' || isdigit(CUR_CHAR) || isexponent(CUR_CHAR)) {
if(CUR_CHAR == '.' || isexponent(CUR_CHAR)) type = TFLOAT;
if(isexponent(CUR_CHAR)) {
if(type != TFLOAT) Error("invalid numeric format");
if(type != TFLOAT) throw CompileException("invalid numeric format");
type = TSCIENTIFIC;
APPEND_CHAR(CUR_CHAR);
NEXT();
@ -444,27 +405,29 @@ SQInteger SQLexer::ReadNumber()
APPEND_CHAR(CUR_CHAR);
NEXT();
}
if(!isdigit(CUR_CHAR)) Error("exponent expected");
if(!isdigit(CUR_CHAR)) throw CompileException("exponent expected");
}
APPEND_CHAR(CUR_CHAR);
NEXT();
}
}
TERMINATE_BUFFER();
switch(type) {
case TSCIENTIFIC:
case TFLOAT:
_fvalue = (SQFloat)strtod(&_longstr[0],&sTemp);
case TFLOAT: {
std::string str{View()};
char *sTemp;
_fvalue = (SQFloat)strtod(str.c_str(),&sTemp);
return TK_FLOAT;
}
case TINT:
LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
_nvalue = ParseInteger<SQUnsignedInteger>(View(), 10).value_or(0);
return TK_INTEGER;
case THEX:
LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
_nvalue = ParseInteger<SQUnsignedInteger>(View(), 16).value_or(0);
return TK_INTEGER;
case TOCTAL:
LexOctal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
_nvalue = ParseInteger<SQUnsignedInteger>(View(), 8).value_or(0);
return TK_INTEGER;
}
return 0;
@ -478,10 +441,6 @@ SQInteger SQLexer::ReadID()
APPEND_CHAR(CUR_CHAR);
NEXT();
} while(isalnum(CUR_CHAR) || CUR_CHAR == '_');
TERMINATE_BUFFER();
res = GetIDType(&_longstr[0]);
if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {
_svalue = &_longstr[0];
}
res = GetIDType(View());
return res;
}

View File

@ -6,11 +6,10 @@ struct SQLexer
{
~SQLexer();
SQLexer(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up);
[[noreturn]] void Error(const SQChar *err);
SQInteger Lex();
const SQChar *Tok2Str(SQInteger tok);
std::optional<std::string_view> Tok2Str(SQInteger tok);
private:
SQInteger GetIDType(SQChar *s);
SQInteger GetIDType(std::string_view s);
SQInteger ReadString(char32_t ndelim,bool verbatim);
SQInteger ReadNumber();
void LexBlockComment();
@ -20,21 +19,21 @@ private:
SQTable *_keywords;
void INIT_TEMP_STRING() { _longstr.resize(0); }
void APPEND_CHAR(char32_t c);
void TERMINATE_BUFFER() { _longstr.push_back('\0'); }
public:
SQInteger _prevtoken;
SQInteger _currentline;
SQInteger _lasttokenline;
SQInteger _currentcolumn;
const SQChar *_svalue;
SQInteger _nvalue;
SQFloat _fvalue;
SQLEXREADFUNC _readf;
SQUserPointer _up;
char32_t _currdata;
SQSharedState *_sharedstate;
sqvector<SQChar> _longstr;
sqvector<char> _longstr;
std::string_view View() const { return std::string_view(_longstr._vals, _longstr.size()); }
};
#endif

View File

@ -18,7 +18,7 @@
#include "../../../safeguards.h"
const SQChar *IdType2Name(SQObjectType type)
std::string_view IdType2Name(SQObjectType type)
{
switch(_RAW_TYPE(type))
{
@ -42,25 +42,25 @@ const SQChar *IdType2Name(SQObjectType type)
case _RT_INSTANCE: return "instance";
case _RT_WEAKREF: return "weakref";
default:
return nullptr;
NOT_REACHED();
}
}
const SQChar *GetTypeName(const SQObjectPtr &obj1)
std::string_view GetTypeName(const SQObjectPtr &obj1)
{
return IdType2Name(type(obj1));
}
SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len)
SQString *SQString::Create(SQSharedState *ss,std::string_view s)
{
SQString *str=ADD_STRING(ss,s,len);
SQString *str=ss->_stringtable->Add(s);
str->_sharedstate=ss;
return str;
}
void SQString::Release()
{
REMOVE_STRING(_sharedstate,this);
_sharedstate->_stringtable->Remove(this);
}
SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
@ -202,24 +202,21 @@ void SQArray::Extend(const SQArray *a){
Append(a->_values[i]);
}
const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop)
std::optional<std::string_view> SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop)
{
SQUnsignedInteger nvars=_nlocalvarinfos;
const SQChar *res=nullptr;
if(nvars>=nseq){
for(SQUnsignedInteger i=0;i<nvars;i++){
if(_localvarinfos[i]._start_op<=nop && _localvarinfos[i]._end_op>=nop)
{
if(_localvarinfos[i]._start_op<=nop && _localvarinfos[i]._end_op>=nop) {
if(nseq==0){
vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]);
res=_stringval(_localvarinfos[i]._name);
break;
return _stringval(_localvarinfos[i]._name);
}
nseq--;
}
}
}
return res;
return std::nullopt;
}
SQInteger SQFunctionProto::GetLine(SQInstruction *curr)
@ -273,10 +270,13 @@ bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o
{
_CHECK_IO(SafeWrite(v,write,up,&type(o),sizeof(SQObjectType)));
switch(type(o)){
case OT_STRING:
_CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger)));
_CHECK_IO(SafeWrite(v,write,up,_stringval(o),_string(o)->_len));
case OT_STRING: {
auto str = _string(o)->Span();
SQInteger len = str.size();
_CHECK_IO(SafeWrite(v,write,up,&len,sizeof(len)));
_CHECK_IO(SafeWrite(v,write,up,str.data(),len));
break;
}
case OT_INTEGER:
_CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break;
case OT_FLOAT:
@ -297,11 +297,11 @@ bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)
switch(t){
case OT_STRING:{
SQInteger len;
_CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger)));
_CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(len),len));
o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len);
}
_CHECK_IO(SafeRead(v,read,up,&len,sizeof(len)));
_CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(len).data(),len));
o=SQString::Create(_ss(v),std::string_view(_ss(v)->GetScratchPad(-1).data(),len));
break;
}
case OT_INTEGER:{
SQInteger i;
_CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break;
@ -323,7 +323,7 @@ bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)
bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)
{
_CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD));
_CHECK_IO(WriteTag(v,write,up,sizeof(SQChar)));
_CHECK_IO(WriteTag(v,write,up,sizeof(char)));
_CHECK_IO(_funcproto(_function)->Save(v,up,write));
_CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL));
return true;
@ -332,7 +332,7 @@ bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)
bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret)
{
_CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD));
_CHECK_IO(CheckTag(v,read,up,sizeof(SQChar)));
_CHECK_IO(CheckTag(v,read,up,sizeof(char)));
SQObjectPtr func;
_CHECK_IO(SQFunctionProto::Load(v,up,read,func));
_CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL));

View File

@ -138,7 +138,7 @@ struct SQObjectPtr;
#define _refcounted(obj) ((obj)._unVal.pRefCounted)
#define _rawval(obj) ((obj)._unVal.raw)
#define _stringval(obj) (obj)._unVal.pString->_val
#define _stringval(obj) (obj)._unVal.pString->View()
#define _userdataval(obj) (obj)._unVal.pUserData->_val
#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num))
@ -357,7 +357,7 @@ struct SQObjectPtr : public SQObject
return *this;
}
private:
SQObjectPtr(const SQChar *){} //safety
SQObjectPtr(const char *) = delete; //safety
};
inline void _Swap(SQObject &a,SQObject &b)
@ -449,8 +449,8 @@ struct SQDelegable : public CHAINABLE_OBJ {
SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx);
typedef sqvector<SQObjectPtr> SQObjectPtrVec;
typedef sqvector<SQInteger> SQIntVec;
const SQChar *GetTypeName(const SQObjectPtr &obj1);
const SQChar *IdType2Name(SQObjectType type);
std::string_view GetTypeName(const SQObjectPtr &obj1);
std::string_view IdType2Name(SQObjectType type);

View File

@ -87,7 +87,7 @@ enum SQOpcode
};
struct SQInstructionDesc {
const SQChar *name;
std::string_view name;
};
struct SQInstruction

View File

@ -14,6 +14,7 @@
#include "sqarray.h"
#include "squserdata.h"
#include "sqclass.h"
#include "../../../core/string_consumer.hpp"
#include "../../../safeguards.h"
@ -32,14 +33,12 @@ SQObjectPtr _minusone_((SQInteger)-1);
_table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
}
bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
bool CompileTypemask(SQIntVec &res,std::string_view typemask)
{
SQInteger i = 0;
SQInteger mask = 0;
while(typemask[i] != 0) {
switch(typemask[i]){
StringConsumer consumer{typemask};
while (consumer.AnyBytesLeft()) {
switch(consumer.ReadChar()){
case 'o': mask |= _RT_NULL; break;
case 'i': mask |= _RT_INTEGER; break;
case 'f': mask |= _RT_FLOAT; break;
@ -56,37 +55,32 @@ bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
case 'x': mask |= _RT_INSTANCE; break;
case 'y': mask |= _RT_CLASS; break;
case 'r': mask |= _RT_WEAKREF; break;
case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
case ' ': i++; continue; //ignores spaces
case '.': mask = -1; res.push_back(mask); mask = 0; continue;
case ' ': continue; //ignores spaces
default:
return false;
}
i++;
if(typemask[i] == '|') {
i++;
if(typemask[i] == 0)
return false;
if(consumer.ReadCharIf('|')) {
if(!consumer.AnyBytesLeft()) return false;
continue;
}
res.push_back(mask);
mask = 0;
}
return true;
}
SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)
SQTable *CreateDefaultDelegate(SQSharedState *ss,const std::initializer_list<SQRegFunction> &funcz)
{
SQInteger i=0;
SQTable *t=SQTable::Create(ss,0);
while(funcz[i].name!=nullptr){
SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f);
nc->_nparamscheck = funcz[i].nparamscheck;
nc->_name = SQString::Create(ss,funcz[i].name);
if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
for (auto &func : funcz) {
SQNativeClosure *nc = SQNativeClosure::Create(ss,func.f);
nc->_nparamscheck = func.nparamscheck;
nc->_name = SQString::Create(ss,func.name);
if(func.typemask.has_value() && !CompileTypemask(nc->_typecheck,*func.typemask))
return nullptr;
t->NewSlot(SQString::Create(ss,funcz[i].name),nc);
i++;
t->NewSlot(SQString::Create(ss,func.name),nc);
}
return t;
}
@ -97,8 +91,6 @@ SQSharedState::SQSharedState()
_printfunc = nullptr;
_debuginfo = false;
_notifyallexceptions = false;
_scratchpad=nullptr;
_scratchpadsize=0;
_collectable_free_processing = false;
#ifndef NO_GARBAGE_COLLECTOR
_gc_chain=nullptr;
@ -212,7 +204,6 @@ SQSharedState::~SQSharedState()
sq_delete(_systemstrings,SQObjectPtrVec);
sq_delete(_metamethods,SQObjectPtrVec);
sq_delete(_stringtable,SQStringTable);
if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
}
@ -357,19 +348,16 @@ void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
}
#endif
SQChar* SQSharedState::GetScratchPad(SQInteger size)
std::span<char> SQSharedState::GetScratchPad(SQInteger size)
{
SQInteger newsize;
if(size>0) {
if(_scratchpadsize < size) {
if(_scratchpad.size() < static_cast<size_t>(size)) {
newsize = size + (size>>1);
_scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
_scratchpadsize = newsize;
}else if(_scratchpadsize >= (size<<5)) {
newsize = _scratchpadsize >> 1;
_scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
_scratchpadsize = newsize;
_scratchpad.resize(newsize);
}else if(_scratchpad.size() >= static_cast<size_t>(size<<5)) {
newsize = _scratchpad.size() >> 1;
_scratchpad.resize(newsize);
}
}
return _scratchpad;
@ -550,36 +538,36 @@ void SQStringTable::AllocNodes(SQInteger size)
{
_numofslots = size;
_strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
memset(_strings,0,sizeof(SQString*)*(size_t)_numofslots);
std::fill_n(_strings, _numofslots, nullptr);
}
SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
static const std::hash<std::string_view> string_table_hash{};
SQString *SQStringTable::Add(std::string_view new_string)
{
if(len<0)
len = (SQInteger)strlen(news);
SQHash h = ::_hashstr(news,(size_t)len)&(_numofslots-1);
size_t len = new_string.size();
auto slot = string_table_hash(new_string) & (_numofslots-1);
SQString *s;
for (s = _strings[h]; s; s = s->_next){
if(s->_len == len && (!memcmp(news,s->_val,(size_t)len)))
return s; //found
for (s = _strings[slot]; s; s = s->_next){
if(s->View() == new_string) return s; //found
}
SQString *t=(SQString *)SQ_MALLOC(len+sizeof(SQString));
new (t) SQString(news, len);
t->_next = _strings[h];
_strings[h] = t;
new (t) SQString(new_string);
t->_next = _strings[slot];
_strings[slot] = t;
_slotused++;
if (_slotused > _numofslots) /* too crowded? */
Resize(_numofslots*2);
return t;
}
SQString::SQString(const SQChar *news, SQInteger len)
SQString::SQString(std::string_view new_string)
{
memcpy(_val,news,(size_t)len);
_val[len] = '\0';
_len = len;
_hash = ::_hashstr(news,(size_t)len);
std::ranges::copy(new_string, _val);
_val[new_string.size()] = '\0';
_len = new_string.size();
_hash = string_table_hash(new_string);
_next = nullptr;
_sharedstate = nullptr;
}
@ -615,7 +603,7 @@ void SQStringTable::Remove(SQString *bs)
else
_strings[h] = s->_next;
_slotused--;
SQInteger slen = s->_len;
size_t slen = s->View().size();
s->~SQString();
SQ_FREE(s,sizeof(SQString) + slen);
return;

View File

@ -13,7 +13,7 @@ struct SQStringTable
{
SQStringTable();
~SQStringTable();
SQString *Add(const SQChar *,SQInteger len);
SQString *Add(std::string_view str);
void Remove(SQString *);
private:
void Resize(SQInteger size);
@ -49,9 +49,6 @@ private:
RefNode **_buckets;
};
#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len)
#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr)
struct SQObjectPtr;
struct SQSharedState
@ -59,7 +56,7 @@ struct SQSharedState
SQSharedState();
~SQSharedState();
public:
SQChar* GetScratchPad(SQInteger size);
std::span<char> GetScratchPad(SQInteger size);
SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name);
void DelayFinalFree(SQCollectable *collectable);
#ifndef NO_GARBAGE_COLLECTOR
@ -84,33 +81,32 @@ public:
#endif
SQObjectPtr _root_vm;
SQObjectPtr _table_default_delegate;
static SQRegFunction _table_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _table_default_delegate_funcz;
SQObjectPtr _array_default_delegate;
static SQRegFunction _array_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _array_default_delegate_funcz;
SQObjectPtr _string_default_delegate;
static SQRegFunction _string_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _string_default_delegate_funcz;
SQObjectPtr _number_default_delegate;
static SQRegFunction _number_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _number_default_delegate_funcz;
SQObjectPtr _generator_default_delegate;
static SQRegFunction _generator_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _generator_default_delegate_funcz;
SQObjectPtr _closure_default_delegate;
static SQRegFunction _closure_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _closure_default_delegate_funcz;
SQObjectPtr _thread_default_delegate;
static SQRegFunction _thread_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _thread_default_delegate_funcz;
SQObjectPtr _class_default_delegate;
static SQRegFunction _class_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _class_default_delegate_funcz;
SQObjectPtr _instance_default_delegate;
static SQRegFunction _instance_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _instance_default_delegate_funcz;
SQObjectPtr _weakref_default_delegate;
static SQRegFunction _weakref_default_delegate_funcz[];
static const std::initializer_list<SQRegFunction> _weakref_default_delegate_funcz;
SQCOMPILERERROR _compilererrorhandler;
SQPRINTFUNCTION _printfunc;
bool _debuginfo;
bool _notifyallexceptions;
private:
SQChar *_scratchpad;
SQInteger _scratchpadsize;
std::vector<char> _scratchpad;
};
#define _sp(s) (_sharedstate->GetScratchPad(s))
@ -133,6 +129,6 @@ extern SQObjectPtr _false_;
extern SQObjectPtr _one_;
extern SQObjectPtr _minusone_;
bool CompileTypemask(SQIntVec &res,const SQChar *typemask);
bool CompileTypemask(SQIntVec &res,std::string_view typemask);
#endif //_SQSTATE_H_

View File

@ -2,29 +2,23 @@
#ifndef _SQSTRING_H_
#define _SQSTRING_H_
inline SQHash _hashstr (const SQChar *s, size_t l)
{
SQHash h = (SQHash)l; /* seed */
size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */
for (; l>=step; l-=step)
h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++));
return h;
}
struct SQString : public SQRefCounted
{
SQString(const SQChar *news, SQInteger len);
SQString(std::string_view str);
~SQString(){}
public:
static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 );
static SQString *Create(SQSharedState *ss, const std::string &str) { return Create(ss, str.data(), str.size()); }
static SQString *Create(SQSharedState *ss, std::string_view str);
SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);
void Release() override;
SQSharedState *_sharedstate;
SQString *_next; //chain for the string table
std::size_t _hash;
std::string_view View() const { return std::string_view(this->_val, this->_len); }
std::span<char> Span() { return std::span<char>(this->_val, this->_len); }
private:
SQInteger _len;
SQHash _hash;
SQChar _val[1];
char _val[1];
};

View File

@ -31,7 +31,7 @@ struct SQUserData : SQDelegable
SQInteger _size;
SQRELEASEHOOK _hook;
SQUserPointer _typetag;
SQChar _val[1];
char _val[1];
};
#endif //_SQUSERDATA_H_

View File

@ -93,7 +93,7 @@ public:
{
_vals[idx].~T();
if(idx < (_size - 1)) {
memmove(static_cast<void *>(&_vals[idx]), &_vals[idx+1], sizeof(T) * (_size - (size_t)idx - 1));
std::move(&_vals[idx + 1], &_vals[_size], &_vals[idx]);
}
_size--;
}

View File

@ -117,7 +117,6 @@ SQVM::SQVM(SQSharedState *ss)
_in_stackoverflow = false;
_ops_till_suspend = 0;
_ops_till_suspend_error_threshold = INT64_MIN;
_ops_till_suspend_error_label = nullptr;
_callsstack = nullptr;
_callsstacksize = 0;
_alloccallsstacksize = 0;
@ -198,7 +197,7 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
SQObjectPtr res;
switch(type(o1)){
case OT_STRING:
_RET_SUCCEED(strcmp(_stringval(o1),_stringval(o2)));
_RET_SUCCEED(_stringval(o1).compare(_stringval(o2)));
case OT_INTEGER:
/* FS#3954: wrong integer comparison */
_RET_SUCCEED((_integer(o1)<_integer(o2))?-1:(_integer(o1)==_integer(o2))?0:1);
@ -302,11 +301,7 @@ bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &
SQObjectPtr a, b;
ToString(str, a);
ToString(obj, b);
SQInteger l = _string(a)->_len , ol = _string(b)->_len;
SQChar *s = _sp(l + ol + 1);
memcpy(s, _stringval(a), (size_t)l);
memcpy(s + l, _stringval(b), (size_t)ol);
dest = SQString::Create(_ss(this), _spval, l + ol);
dest = SQString::Create(_ss(this), fmt::format("{}{}", _stringval(a), _stringval(b)));
return true;
}
@ -1253,7 +1248,8 @@ bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,
if(fetchroot) {
if(_rawval(STK(0)) == _rawval(self) &&
type(STK(0)) == type(self)) {
return _table(_roottable)->Get(key,dest);
if (_table(_roottable)->Get(key,dest)) return true;
return _table(_ss(this)->_consts)->Get(key,dest);
}
}
return false;
@ -1288,9 +1284,10 @@ bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPt
case OT_STRING:
if(sq_isnumeric(key)){
SQInteger n=tointeger(key);
if(abs((int)n)<_string(self)->_len){
if(n<0)n=_string(self)->_len-n;
dest=SQInteger(_stringval(self)[n]);
std::string_view str = _stringval(self);
if(std::abs(n) < static_cast<SQInteger>(str.size())){
if(n<0)n=str.size()+n;
dest=SQInteger(str[n]);
return true;
}
return false;

View File

@ -169,7 +169,7 @@ public:
SQBool _can_suspend;
SQInteger _ops_till_suspend;
SQInteger _ops_till_suspend_error_threshold;
const char *_ops_till_suspend_error_label;
std::string_view _ops_till_suspend_error_label;
SQBool _in_stackoverflow;
bool ShouldSuspend()

View File

@ -279,6 +279,10 @@ add_files(
newgrf_animation_type.h
newgrf_badge.cpp
newgrf_badge.h
newgrf_badge_config.cpp
newgrf_badge_config.h
newgrf_badge_gui.cpp
newgrf_badge_gui.h
newgrf_badge_type.h
newgrf_callbacks.h
newgrf_canal.cpp
@ -450,6 +454,7 @@ add_files(
spritecache.cpp
spritecache.h
spritecache_internal.h
spritecache_type.h
station.cpp
station_base.h
station_cmd.cpp

View File

@ -84,7 +84,7 @@ static constexpr NWidgetPart _nested_ai_config_widgets[] = {
/** Window definition for the configure AI window. */
static WindowDesc _ai_config_desc(
WDP_CENTER, nullptr, 0, 0,
WDP_CENTER, {}, 0, 0,
WC_GAME_OPTIONS, WC_NONE,
{},
_nested_ai_config_widgets
@ -142,7 +142,7 @@ struct AIConfigWindow : public Window {
case WID_AIC_LIST:
this->line_height = GetCharacterHeight(FS_NORMAL) + padding.height;
resize.height = this->line_height;
fill.height = resize.height = this->line_height;
size.height = 8 * this->line_height;
break;
}
@ -218,7 +218,7 @@ struct AIConfigWindow : public Window {
if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_CONTENT_END) {
if (this->selected_slot == CompanyID::Invalid() || AIConfig::GetConfig(this->selected_slot) == nullptr) return;
ShowScriptTextfileWindow((TextfileType)(widget - WID_AIC_TEXTFILE), this->selected_slot);
ShowScriptTextfileWindow(this, static_cast<TextfileType>(widget - WID_AIC_TEXTFILE), this->selected_slot);
return;
}
@ -250,23 +250,23 @@ struct AIConfigWindow : public Window {
}
case WID_AIC_LIST: { // Select a slot
this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
this->selected_slot = static_cast<CompanyID>(this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget));
this->InvalidateData();
if (click_count > 1 && IsEditable(this->selected_slot)) ShowScriptListWindow((CompanyID)this->selected_slot, _ctrl_pressed);
if (click_count > 1 && IsEditable(this->selected_slot)) ShowScriptListWindow(this->selected_slot, _ctrl_pressed);
break;
}
case WID_AIC_MOVE_UP:
if (IsEditable(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot - 1))) {
if (IsEditable(this->selected_slot) && IsEditable(static_cast<CompanyID>(this->selected_slot - 1))) {
std::swap(GetGameSettings().script_config.ai[this->selected_slot], GetGameSettings().script_config.ai[this->selected_slot - 1]);
this->selected_slot = CompanyID(this->selected_slot - 1);
this->selected_slot = static_cast<CompanyID>(this->selected_slot - 1);
this->vscroll->ScrollTowards(this->selected_slot.base());
this->InvalidateData();
}
break;
case WID_AIC_MOVE_DOWN:
if (IsEditable(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot + 1))) {
if (IsEditable(this->selected_slot) && IsEditable(static_cast<CompanyID>(this->selected_slot + 1))) {
std::swap(GetGameSettings().script_config.ai[this->selected_slot], GetGameSettings().script_config.ai[this->selected_slot + 1]);
++this->selected_slot;
this->vscroll->ScrollTowards(this->selected_slot.base());
@ -282,11 +282,11 @@ struct AIConfigWindow : public Window {
}
case WID_AIC_CHANGE: // choose other AI
if (IsEditable(this->selected_slot)) ShowScriptListWindow((CompanyID)this->selected_slot, _ctrl_pressed);
if (IsEditable(this->selected_slot)) ShowScriptListWindow(this->selected_slot, _ctrl_pressed);
break;
case WID_AIC_CONFIGURE: // change the settings for an AI
ShowScriptSettingsWindow((CompanyID)this->selected_slot);
ShowScriptSettingsWindow(this->selected_slot);
break;
case WID_AIC_CONTENT_DOWNLOAD:
@ -320,8 +320,8 @@ struct AIConfigWindow : public Window {
this->SetWidgetDisabledState(WID_AIC_INCREASE_INTERVAL, GetGameSettings().difficulty.competitors_interval == MAX_COMPETITORS_INTERVAL);
this->SetWidgetDisabledState(WID_AIC_CHANGE, !IsEditable(this->selected_slot));
this->SetWidgetDisabledState(WID_AIC_CONFIGURE, this->selected_slot == CompanyID::Invalid() || config->GetConfigList()->empty());
this->SetWidgetDisabledState(WID_AIC_MOVE_UP, !IsEditable(this->selected_slot) || !IsEditable((CompanyID)(this->selected_slot - 1)));
this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, !IsEditable(this->selected_slot) || !IsEditable((CompanyID)(this->selected_slot + 1)));
this->SetWidgetDisabledState(WID_AIC_MOVE_UP, !IsEditable(this->selected_slot) || !IsEditable(static_cast<CompanyID>(this->selected_slot - 1)));
this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, !IsEditable(this->selected_slot) || !IsEditable(static_cast<CompanyID>(this->selected_slot + 1)));
this->SetWidgetDisabledState(WID_AIC_OPEN_URL, this->selected_slot == CompanyID::Invalid() || config->GetInfo() == nullptr || config->GetInfo()->GetURL().empty());
for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {

View File

@ -27,14 +27,14 @@ static bool CheckAPIVersion(const std::string &api_version)
return std::ranges::find(AIInfo::ApiVersions, api_version) != std::end(AIInfo::ApiVersions);
}
template <> SQInteger PushClassName<AIInfo, ScriptType::AI>(HSQUIRRELVM vm) { sq_pushstring(vm, "AIInfo", -1); return 1; }
template <> SQInteger PushClassName<AIInfo, ScriptType::AI>(HSQUIRRELVM vm) { sq_pushstring(vm, "AIInfo"); return 1; }
/* static */ void AIInfo::RegisterAPI(Squirrel *engine)
/* static */ void AIInfo::RegisterAPI(Squirrel &engine)
{
/* Create the AIInfo class, and add the RegisterAI function */
DefSQClass<AIInfo, ScriptType::AI> SQAIInfo("AIInfo");
SQAIInfo.PreRegister(engine);
SQAIInfo.AddConstructor<void (AIInfo::*)(), 1>(engine, "x");
SQAIInfo.AddConstructor<void (AIInfo::*)()>(engine, "x");
SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddSetting, "AddSetting");
SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddLabels, "AddLabels");
SQAIInfo.DefSQConst(engine, ScriptConfigFlags{}.base(), "CONFIG_NONE");
@ -50,8 +50,8 @@ template <> SQInteger PushClassName<AIInfo, ScriptType::AI>(HSQUIRRELVM vm) { sq
SQAIInfo.DefSQConst(engine, ScriptConfigFlags{ScriptConfigFlag::InGame}.base(), "AICONFIG_INGAME");
SQAIInfo.PostRegister(engine);
engine->AddMethod("RegisterAI", &AIInfo::Constructor, 2, "tx");
engine->AddMethod("RegisterDummyAI", &AIInfo::DummyConstructor, 2, "tx");
engine.AddMethod("RegisterAI", &AIInfo::Constructor, "tx");
engine.AddMethod("RegisterDummyAI", &AIInfo::DummyConstructor, "tx");
}
/* static */ SQInteger AIInfo::Constructor(HSQUIRRELVM vm)
@ -61,11 +61,12 @@ template <> SQInteger PushClassName<AIInfo, ScriptType::AI>(HSQUIRRELVM vm) { sq
if (SQ_FAILED(sq_getinstanceup(vm, 2, &instance, nullptr)) || instance == nullptr) return sq_throwerror(vm, "Pass an instance of a child class of AIInfo to RegisterAI");
AIInfo *info = (AIInfo *)instance;
SQInteger res = ScriptInfo::Constructor(vm, info);
SQInteger res = ScriptInfo::Constructor(vm, *info);
if (res != 0) return res;
if (info->engine->MethodExists(info->SQ_instance, "MinVersionToLoad")) {
if (!info->engine->CallIntegerMethod(info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
if (info->min_loadable_version < 0) return SQ_ERROR;
} else {
info->min_loadable_version = info->GetVersion();
}
@ -89,7 +90,7 @@ template <> SQInteger PushClassName<AIInfo, ScriptType::AI>(HSQUIRRELVM vm) { sq
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
sq_setinstanceup(vm, 2, nullptr);
/* Register the AI to the base system */
info->GetScanner()->RegisterScript(info);
info->GetScanner()->RegisterScript(std::unique_ptr<AIInfo>{info});
return 0;
}
@ -101,13 +102,13 @@ template <> SQInteger PushClassName<AIInfo, ScriptType::AI>(HSQUIRRELVM vm) { sq
AIInfo *info = (AIInfo *)instance;
info->api_version = *std::rbegin(AIInfo::ApiVersions);
SQInteger res = ScriptInfo::Constructor(vm, info);
SQInteger res = ScriptInfo::Constructor(vm, *info);
if (res != 0) return res;
/* Remove the link to the real instance, else it might get deleted by RegisterAI() */
sq_setinstanceup(vm, 2, nullptr);
/* Register the AI to the base system */
static_cast<AIScannerInfo *>(info->GetScanner())->SetDummyAI(info);
static_cast<AIScannerInfo *>(info->GetScanner())->SetDummyAI(std::unique_ptr<AIInfo>(info));
return 0;
}
@ -124,33 +125,32 @@ bool AIInfo::CanLoadFromVersion(int version) const
}
/* static */ void AILibrary::RegisterAPI(Squirrel *engine)
/* static */ void AILibrary::RegisterAPI(Squirrel &engine)
{
/* Create the AILibrary class, and add the RegisterLibrary function */
engine->AddClassBegin("AILibrary");
engine->AddClassEnd();
engine->AddMethod("RegisterLibrary", &AILibrary::Constructor, 2, "tx");
engine.AddClassBegin("AILibrary");
engine.AddClassEnd();
engine.AddMethod("RegisterLibrary", &AILibrary::Constructor, "tx");
}
/* static */ SQInteger AILibrary::Constructor(HSQUIRRELVM vm)
{
/* Create a new library */
AILibrary *library = new AILibrary();
auto library = std::make_unique<AILibrary>();
SQInteger res = ScriptInfo::Constructor(vm, library);
SQInteger res = ScriptInfo::Constructor(vm, *library);
if (res != 0) {
delete library;
return res;
}
/* Cache the category */
if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethod(library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) {
delete library;
return SQ_ERROR;
}
/* Register the Library to the base system */
library->GetScanner()->RegisterScript(library);
ScriptScanner *scanner = library->GetScanner();
scanner->RegisterScript(std::move(library));
return 0;
}

View File

@ -23,7 +23,7 @@ public:
/**
* Register the functions of this class.
*/
static void RegisterAPI(Squirrel *engine);
static void RegisterAPI(Squirrel &engine);
/**
* Create an AI, using this AIInfo as start-template.
@ -64,7 +64,7 @@ public:
/**
* Register the functions of this class.
*/
static void RegisterAPI(Squirrel *engine);
static void RegisterAPI(Squirrel &engine);
/**
* Create an AI, using this AIInfo as start-template.

View File

@ -27,7 +27,7 @@
#include "table/strings.h"
/* Manually include the Text glue. */
#include "../script/api/template/template_text.hpp.sq"
#include "../script/api/template/template_text.sq.hpp"
/* Convert all AI related classes to Squirrel data. */
#include "../script/api/ai/ai_includes.hpp"
@ -43,7 +43,7 @@ void AIInstance::Initialize(AIInfo *info)
this->api_version = info->GetAPIVersion();
/* Register the AIController (including the "import" command) */
SQAIController_Register(this->engine);
SQAIController_Register(*this->engine);
ScriptInstance::Initialize(info->GetMainScript(), info->GetInstanceName(), _current_company);
}
@ -53,7 +53,7 @@ void AIInstance::RegisterAPI()
ScriptInstance::RegisterAPI();
/* Register all classes */
SQAI_RegisterAll(this->engine);
SQAI_RegisterAll(*this->engine);
if (!this->LoadCompatibilityScripts(AI_DIR, AIInfo::ApiVersions)) this->Died();
}
@ -83,7 +83,7 @@ void AIInstance::Died()
void AIInstance::LoadDummyScript()
{
ScriptAllocatorScope alloc_scope(this->engine);
ScriptAllocatorScope alloc_scope(this->engine.get());
Script_CreateDummy(this->engine->GetVM(), STR_ERROR_AI_NO_AI_FOUND, "AI");
}

View File

@ -22,39 +22,31 @@
#include "../safeguards.h"
AIScannerInfo::AIScannerInfo() :
ScriptScanner(),
info_dummy(nullptr)
{
}
AIScannerInfo::AIScannerInfo() = default;
AIScannerInfo::~AIScannerInfo() = default;
void AIScannerInfo::Initialize()
{
ScriptScanner::Initialize("AIScanner");
ScriptAllocatorScope alloc_scope(this->engine);
ScriptAllocatorScope alloc_scope(this->engine.get());
/* Create the dummy AI */
this->main_script = "%_dummy";
Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai");
}
void AIScannerInfo::SetDummyAI(class AIInfo *info)
void AIScannerInfo::SetDummyAI(std::unique_ptr<class AIInfo> &&info)
{
this->info_dummy = info;
this->info_dummy = std::move(info);
}
AIScannerInfo::~AIScannerInfo()
std::string AIScannerInfo::GetScriptName(ScriptInfo &info)
{
delete this->info_dummy;
return info.GetName();
}
std::string AIScannerInfo::GetScriptName(ScriptInfo *info)
{
return info->GetName();
}
void AIScannerInfo::RegisterAPI(class Squirrel *engine)
void AIScannerInfo::RegisterAPI(class Squirrel &engine)
{
AIInfo::RegisterAPI(engine);
}
@ -63,7 +55,7 @@ AIInfo *AIScannerInfo::SelectRandomAI() const
{
if (_game_mode == GM_MENU) {
Debug(script, 0, "The intro game should not use AI, loading 'dummy' AI.");
return this->info_dummy;
return this->info_dummy.get();
}
/* Filter for AIs suitable as Random AI. */
@ -72,7 +64,7 @@ AIInfo *AIScannerInfo::SelectRandomAI() const
uint num_random_ais = std::ranges::distance(random_ais);
if (num_random_ais == 0) {
Debug(script, 0, "No suitable AI found, loading 'dummy' AI.");
return this->info_dummy;
return this->info_dummy.get();
}
/* Pick a random AI */
@ -125,13 +117,13 @@ void AIScannerLibrary::Initialize()
ScriptScanner::Initialize("AIScanner");
}
std::string AIScannerLibrary::GetScriptName(ScriptInfo *info)
std::string AIScannerLibrary::GetScriptName(ScriptInfo &info)
{
AILibrary *library = static_cast<AILibrary *>(info);
return fmt::format("{}.{}", library->GetCategory(), library->GetInstanceName());
AILibrary &library = static_cast<AILibrary &>(info);
return fmt::format("{}.{}", library.GetCategory(), library.GetInstanceName());
}
void AIScannerLibrary::RegisterAPI(class Squirrel *engine)
void AIScannerLibrary::RegisterAPI(class Squirrel &engine)
{
AILibrary::RegisterAPI(engine);
}

View File

@ -37,17 +37,17 @@ public:
/**
* Set the Dummy AI.
*/
void SetDummyAI(class AIInfo *info);
void SetDummyAI(std::unique_ptr<class AIInfo> &&info);
protected:
std::string GetScriptName(ScriptInfo *info) override;
const char *GetFileName() const override { return PATHSEP "info.nut"; }
std::string GetScriptName(ScriptInfo &info) override;
std::string_view GetFileName() const override { return PATHSEP "info.nut"; }
Subdirectory GetDirectory() const override { return AI_DIR; }
const char *GetScannerName() const override { return "AIs"; }
void RegisterAPI(class Squirrel *engine) override;
std::string_view GetScannerName() const override { return "AIs"; }
void RegisterAPI(class Squirrel &engine) override;
private:
AIInfo *info_dummy; ///< The dummy AI.
std::unique_ptr<AIInfo> info_dummy; ///< The dummy AI.
};
class AIScannerLibrary : public ScriptScanner {
@ -63,11 +63,11 @@ public:
class AILibrary *FindLibrary(const std::string &library, int version);
protected:
std::string GetScriptName(ScriptInfo *info) override;
const char *GetFileName() const override { return PATHSEP "library.nut"; }
std::string GetScriptName(ScriptInfo &info) override;
std::string_view GetFileName() const override { return PATHSEP "library.nut"; }
Subdirectory GetDirectory() const override { return AI_LIBRARY_DIR; }
const char *GetScannerName() const override { return "AI Libraries"; }
void RegisterAPI(class Squirrel *engine) override;
std::string_view GetScannerName() const override { return "AI Libraries"; }
void RegisterAPI(class Squirrel &engine) override;
};
#endif /* AI_SCANNER_HPP */

View File

@ -175,7 +175,7 @@ void Aircraft::GetImage(Direction direction, EngineImageType image_type, Vehicle
{
uint8_t spritenum = this->spritenum;
if (is_custom_sprite(spritenum)) {
if (IsCustomVehicleSpriteNum(spritenum)) {
GetCustomVehicleSprite(this, direction, image_type, result);
if (result->IsValid()) return;
@ -191,7 +191,7 @@ void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteS
assert(v->subtype == AIR_HELICOPTER);
const Aircraft *w = v->Next()->Next();
if (is_custom_sprite(v->spritenum)) {
if (IsCustomVehicleSpriteNum(v->spritenum)) {
GetCustomRotorSprite(v, image_type, result);
if (result->IsValid()) return;
}
@ -205,7 +205,7 @@ static void GetAircraftIcon(EngineID engine, EngineImageType image_type, Vehicle
const Engine *e = Engine::Get(engine);
uint8_t spritenum = e->u.air.image_index;
if (is_custom_sprite(spritenum)) {
if (IsCustomVehicleSpriteNum(spritenum)) {
GetCustomVehicleIcon(engine, DIR_W, image_type, result);
if (result->IsValid()) return;
@ -1125,6 +1125,15 @@ static bool AircraftController(Aircraft *v)
}
if (amd.flags.Test(AirportMovingDataFlag::Land)) {
if (st->airport.blocks.Test(AirportBlock::Zeppeliner)) {
/* Zeppeliner blocked the runway, abort landing */
v->state = FLYING;
UpdateAircraftCache(v);
SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlightLevel(v));
v->pos = v->previous_pos;
continue;
}
if (st->airport.tile == INVALID_TILE) {
/* Airport has been removed, abort the landing procedure */
v->state = FLYING;
@ -1430,7 +1439,7 @@ static void AircraftLandAirplane(Aircraft *v)
v->UpdateDeltaXY();
AirportTileAnimationTrigger(st, vt, AAT_STATION_AIRPLANE_LAND);
TriggerAirportTileAnimation(st, vt, AirportAnimationTrigger::AirplaneTouchdown);
if (!PlayVehicleSound(v, VSE_TOUCHDOWN)) {
SndPlayVehicleFx(SND_17_SKID_PLANE, v);
@ -1782,6 +1791,11 @@ static void AirportClearBlock(const Aircraft *v, const AirportFTAClass *apc)
if (apc->layout[v->previous_pos].blocks != apc->layout[v->pos].blocks) {
Station *st = Station::Get(v->targetairport);
if (st->airport.blocks.Test(AirportBlock::Zeppeliner) &&
apc->layout[v->previous_pos].blocks == AirportBlock::RunwayIn) {
return;
}
st->airport.blocks.Reset(apc->layout[v->previous_pos].blocks);
}
}

View File

@ -44,7 +44,7 @@ enum AirportTypes : uint8_t {
};
/** Flags for airport movement data. */
enum AirportMovingDataFlag : uint8_t {
enum class AirportMovingDataFlag : uint8_t {
NoSpeedClamp, ///< No speed restrictions.
Takeoff, ///< Takeoff movement.
SlowTurn, ///< Turn slowly (mostly used in the air).
@ -127,6 +127,7 @@ enum class AirportBlock : uint8_t {
/* end of new blocks */
Nothing = 30,
Zeppeliner = 62, ///< Block for the zeppeliner disaster vehicle.
AirportClosed = 63, ///< Dummy block for indicating a closed airport.
};
using AirportBlocks = EnumBitSet<AirportBlock, uint64_t>;

View File

@ -21,7 +21,7 @@
#include "company_base.h"
#include "station_type.h"
#include "newgrf_airport.h"
#include "newgrf_badge.h"
#include "newgrf_badge_gui.h"
#include "newgrf_callbacks.h"
#include "dropdown_type.h"
#include "dropdown_func.h"
@ -204,9 +204,9 @@ static constexpr NWidgetPart _nested_air_toolbar_widgets[] = {
NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_AIRPORT), SetFill(0, 1), SetMinimalSize(42, 22), SetSpriteTip(SPR_IMG_AIRPORT, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetFill(1, 1), EndContainer(),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetSpriteTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_AIRPORT), SetFill(0, 1), SetToolbarMinimalSize(2), SetSpriteTip(SPR_IMG_AIRPORT, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetToolbarSpacerMinimalSize(), SetFill(1, 1), EndContainer(),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_DEMOLISH), SetFill(0, 1), SetToolbarMinimalSize(1), SetSpriteTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
EndContainer(),
};
@ -401,7 +401,7 @@ public:
case WID_AP_AIRPORT_SPRITE:
if (this->preview_sprite != 0) {
Dimension d = GetSpriteSize(this->preview_sprite);
DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), CentreBounds(r.left, r.right, d.width), CentreBounds(r.top, r.bottom, d.height));
DrawSprite(this->preview_sprite, GetCompanyPalette(_local_company), CentreBounds(r.left, r.right, d.width), CentreBounds(r.top, r.bottom, d.height));
}
break;
@ -561,7 +561,7 @@ public:
this->SelectOtherAirport(-1);
}
void OnDropdownSelect(WidgetID widget, int index) override
void OnDropdownSelect(WidgetID widget, int index, int) override
{
if (widget == WID_AP_CLASS_DROPDOWN) {
_selected_airport_class = (AirportClassID)index;
@ -575,7 +575,7 @@ public:
CheckRedrawStationCoverage(this);
}
IntervalTimer<TimerGameCalendar> yearly_interval = {{TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE}, [this](auto) {
const IntervalTimer<TimerGameCalendar> yearly_interval = {{TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE}, [this](auto) {
this->InvalidateData();
}};
};
@ -618,7 +618,7 @@ static constexpr NWidgetPart _nested_build_airport_widgets[] = {
};
static WindowDesc _build_airport_desc(
WDP_AUTO, nullptr, 0, 0,
WDP_AUTO, {}, 0, 0,
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WindowDefaultFlag::Construction,
_nested_build_airport_widgets

View File

@ -80,20 +80,18 @@ uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
* either, so it doesn't matter how many articulated parts there are. */
if (!Vehicle::CanAllocateItem()) return 0;
Vehicle *v = nullptr;
std::unique_ptr<Vehicle> v;
if (!purchase_window) {
v = new Vehicle();
v = std::make_unique<Vehicle>();
v->engine_type = engine_type;
v->owner = _current_company;
}
uint i;
for (i = 1; i < MAX_ARTICULATED_PARTS; i++) {
if (GetNextArticulatedPart(i, engine_type, v) == EngineID::Invalid()) break;
if (GetNextArticulatedPart(i, engine_type, v.get()) == EngineID::Invalid()) break;
}
delete v;
return i - 1;
}
@ -432,7 +430,10 @@ void AddArticulatedParts(Vehicle *first)
if (flip_image) v->spritenum++;
if (v->type == VEH_TRAIN && TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed)) SetBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION);
if (v->type == VEH_TRAIN) {
auto prob = TestVehicleBuildProbability(v, v->engine_type, BuildProbabilityType::Reversed);
if (prob.has_value()) Train::From(v)->flags.Set(VehicleRailFlag::Flipped, prob.value());
}
v->UpdatePosition();
}
}

View File

@ -17,9 +17,12 @@
#include "safeguards.h"
/**
* @return true, if the textbuf was updated.
*/
bool AutoCompletion::AutoComplete()
{
// We are pressing TAB for the first time after reset.
/* We are pressing TAB for the first time after reset. */
if (this->suggestions.empty()) {
this->InitSuggestions(this->textbuf->GetText());
if (this->suggestions.empty()) {
@ -29,11 +32,11 @@ bool AutoCompletion::AutoComplete()
return true;
}
// We are pressing TAB again on the same text.
/* We are pressing TAB again on the same text. */
if (this->current_suggestion_index + 1 < this->suggestions.size()) {
this->ApplySuggestion(prefix, this->suggestions[++this->current_suggestion_index]);
} else {
// We are out of options, restore original text.
/* We are out of options, restore original text. */
this->textbuf->Assign(initial_buf);
this->Reset();
}

View File

@ -32,7 +32,6 @@ public:
}
virtual ~AutoCompletion() = default;
// Returns true the textbuf was updated.
bool AutoComplete();
void Reset();

View File

@ -185,9 +185,9 @@ static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, EngineID engine_ty
CargoTypes union_refit_mask_b = GetUnionOfArticulatedRefitMasks(engine_type, false);
const Vehicle *u = (v->type == VEH_TRAIN) ? v->First() : v;
for (const Order *o : u->Orders()) {
if (!o->IsRefit() || o->IsAutoRefit()) continue;
CargoType cargo_type = o->GetRefitCargo();
for (const Order &o : u->Orders()) {
if (!o.IsRefit() || o.IsAutoRefit()) continue;
CargoType cargo_type = o.GetRefitCargo();
if (!HasBit(union_refit_mask_a, cargo_type)) continue;
if (!HasBit(union_refit_mask_b, cargo_type)) return false;
@ -206,13 +206,12 @@ static int GetIncompatibleRefitOrderIdForAutoreplace(const Vehicle *v, EngineID
{
CargoTypes union_refit_mask = GetUnionOfArticulatedRefitMasks(engine_type, false);
const Order *o;
const Vehicle *u = (v->type == VEH_TRAIN) ? v->First() : v;
const OrderList *orders = u->orders;
if (orders == nullptr) return -1;
for (VehicleOrderID i = 0; i < orders->GetNumOrders(); i++) {
o = orders->GetOrderAt(i);
const Order *o = orders->GetOrderAt(i);
if (!o->IsRefit()) continue;
if (!HasBit(union_refit_mask, o->GetRefitCargo())) return i;
}
@ -373,8 +372,12 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic
}
/* Try to reverse the vehicle, but do not care if it fails as the new type might not be reversible */
if (new_veh->type == VEH_TRAIN && HasBit(Train::From(old_veh)->flags, VRF_REVERSE_DIRECTION)) {
Command<CMD_REVERSE_TRAIN_DIRECTION>::Do(DoCommandFlag::Execute, new_veh->index, true);
if (new_veh->type == VEH_TRAIN && Train::From(old_veh)->flags.Test(VehicleRailFlag::Flipped)) {
/* Only copy the reverse state if neither old or new vehicle implements reverse-on-build probability callback. */
if (!TestVehicleBuildProbability(old_veh, old_veh->engine_type, BuildProbabilityType::Reversed).has_value() &&
!TestVehicleBuildProbability(new_veh, new_veh->engine_type, BuildProbabilityType::Reversed).has_value()) {
Command<CMD_REVERSE_TRAIN_DIRECTION>::Do(DoCommandFlag::Execute, new_veh->index, true);
}
}
return cost;

View File

@ -122,7 +122,7 @@ class ReplaceVehicleWindow : public Window {
*/
void GenerateReplaceVehList(bool draw_left)
{
std::vector<EngineID> variants;
FlatSet<EngineID> variants;
EngineID selected_engine = EngineID::Invalid();
VehicleType type = this->window_number;
uint8_t side = draw_left ? 0 : 1;
@ -161,8 +161,7 @@ class ReplaceVehicleWindow : public Window {
if (side == 1) {
EngineID parent = e->info.variant_id;
while (parent != EngineID::Invalid()) {
variants.push_back(parent);
while (parent != EngineID::Invalid() && variants.insert(parent).second) {
parent = Engine::Get(parent)->info.variant_id;
}
}
@ -311,7 +310,7 @@ public:
case WID_RV_LEFT_MATRIX:
case WID_RV_RIGHT_MATRIX:
resize.height = GetEngineListHeight(this->window_number);
fill.height = resize.height = GetEngineListHeight(this->window_number);
size.height = (this->window_number <= VEH_ROAD ? 8 : 4) * resize.height;
break;
@ -406,11 +405,11 @@ public:
case WID_RV_TRAIN_WAGONREMOVE_TOGGLE:
if (const Group *g = Group::GetIfValid(this->sel_group); g != nullptr) {
bool remove_wagon = g->flags.Test(GroupFlag::ReplaceWagonRemoval);
return GetString(STR_GROUP_NAME, sel_group, remove_wagon ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
return GetString(STR_REPLACE_REMOVE_WAGON, STR_GROUP_NAME, sel_group, remove_wagon ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
} else {
const Company *c = Company::Get(_local_company);
bool remove_wagon = c->settings.renew_keep_length;
return GetString(STR_GROUP_DEFAULT_TRAINS + this->window_number, std::monostate{}, remove_wagon ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
return GetString(STR_REPLACE_REMOVE_WAGON, STR_GROUP_DEFAULT_TRAINS + this->window_number, std::monostate{}, remove_wagon ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
}
break;
@ -552,7 +551,7 @@ public:
if (g != nullptr) {
Command<CMD_SET_GROUP_FLAG>::Post(this->sel_group, GroupFlag::ReplaceWagonRemoval, !g->flags.Test(GroupFlag::ReplaceWagonRemoval), _ctrl_pressed);
} else {
// toggle renew_keep_length
/* toggle renew_keep_length */
Command<CMD_CHANGE_COMPANY_SETTING>::Post("company.renew_keep_length", Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1);
}
break;
@ -623,7 +622,7 @@ public:
}
}
void OnDropdownSelect(WidgetID widget, int index) override
void OnDropdownSelect(WidgetID widget, int index, int) override
{
switch (widget) {
case WID_RV_SORT_DROPDOWN:
@ -744,7 +743,7 @@ static constexpr NWidgetPart _nested_replace_rail_vehicle_widgets[] = {
NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(),
NWidget(NWID_VERTICAL),
NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_WAGONREMOVE_TOGGLE), SetMinimalSize(138, 12), SetStringTip(STR_REPLACE_REMOVE_WAGON, STR_REPLACE_REMOVE_WAGON_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_WAGONREMOVE_TOGGLE), SetMinimalSize(138, 12), SetToolTip(STR_REPLACE_REMOVE_WAGON_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL),

View File

@ -16,8 +16,9 @@
#include "3rdparty/md5/md5.h"
#include <unordered_map>
/* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */
struct IniFile;
struct IniGroup;
struct IniItem;
struct ContentInfo;
/** Structure holding filename and MD5 information about a single file */
@ -47,7 +48,7 @@ template <class T> struct BaseSetTraits;
*/
template <class T>
struct BaseSet {
typedef std::unordered_map<std::string, std::string> TranslatedStrings;
typedef std::unordered_map<std::string, std::string, StringHash, std::equal_to<>> TranslatedStrings;
/** Number of files in this set */
static constexpr size_t NUM_FILES = BaseSetTraits<T>::num_files;
@ -62,21 +63,13 @@ struct BaseSet {
std::string url; ///< URL for information about the base set
TranslatedStrings description; ///< Description of the base set
uint32_t shortname = 0; ///< Four letter short variant of the name
uint32_t version = 0; ///< The version of this base set
std::vector<uint32_t> version; ///< The version of this base set
bool fallback = false; ///< This set is a fallback set, i.e. it should be used only as last resort
std::array<MD5File, BaseSet<T>::NUM_FILES> files{}; ///< All files part of this set
uint found_files = 0; ///< Number of the files that could be found
uint valid_files = 0; ///< Number of the files that could be found and are valid
T *next = nullptr; ///< The next base set in this list
/** Free everything we allocated */
~BaseSet()
{
delete this->next;
}
/**
* Get the number of missing files.
* @return the number
@ -96,6 +89,9 @@ struct BaseSet {
return BaseSet<T>::NUM_FILES - this->valid_files;
}
void LogError(std::string_view full_filename, std::string_view detail, int level = 0) const;
const IniItem *GetMandatoryItem(std::string_view full_filename, const IniGroup &group, std::string_view name) const;
bool FillSetDetails(const IniFile &ini, const std::string &path, const std::string &full_filename, bool allow_empty_filename = true);
void CopyCompatibleConfig([[maybe_unused]] const T &src) {}
@ -107,7 +103,7 @@ struct BaseSet {
* @param isocode the isocode to search for
* @return the description
*/
const std::string &GetDescription(const std::string &isocode) const
const std::string &GetDescription(std::string_view isocode) const
{
if (!isocode.empty()) {
/* First the full ISO code */
@ -166,9 +162,9 @@ struct BaseSet {
template <class Tbase_set>
class BaseMedia : FileScanner {
protected:
static inline Tbase_set *available_sets = nullptr; ///< All available sets
static inline Tbase_set *duplicate_sets = nullptr; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded.
static inline const Tbase_set *used_set = nullptr; ///< The currently used set
static inline std::vector<std::unique_ptr<Tbase_set>> available_sets; ///< All available sets
static inline std::vector<std::unique_ptr<Tbase_set>> duplicate_sets; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded.
static inline const Tbase_set *used_set; ///< The currently used set
bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override;
@ -176,7 +172,13 @@ protected:
* Get the extension that is used to identify this set.
* @return the extension
*/
static const char *GetExtension();
static std::string_view GetExtension();
/**
* Return the duplicate sets.
* @return The duplicate sets.
*/
static std::span<const std::unique_ptr<Tbase_set>> GetDuplicateSets() { return BaseMedia<Tbase_set>::duplicate_sets; }
public:
/**
* Determine the graphics pack that has to be used.
@ -194,7 +196,11 @@ public:
return num + fs.Scan(GetExtension(), BASESET_DIR, Tbase_set::SEARCH_IN_TARS);
}
static Tbase_set *GetAvailableSets();
/**
* Return the available sets.
* @return The available sets.
*/
static std::span<const std::unique_ptr<Tbase_set>> GetAvailableSets() { return BaseMedia<Tbase_set>::available_sets; }
static bool SetSet(const Tbase_set *set);
static bool SetSetByName(const std::string &name);
@ -219,9 +225,9 @@ public:
* @param ci The content info to compare it to.
* @param md5sum Should the MD5 checksum be tested as well?
* @param s The list with sets.
* @return The filename of the first file of the base set, or \c nullptr if there is no match.
* @return The filename of the first file of the base set, or \c std::nullopt if there is no match.
*/
template <class Tbase_set>
const char *TryGetBaseSetFile(const ContentInfo &ci, bool md5sum, const Tbase_set *s);
std::optional<std::string_view> TryGetBaseSetFile(const ContentInfo &ci, bool md5sum, std::span<const std::unique_ptr<Tbase_set>> sets);
#endif /* BASE_MEDIA_BASE_H */

View File

@ -14,20 +14,39 @@
#include "ini_type.h"
#include "string_func.h"
#include "error_func.h"
#include "core/string_consumer.hpp"
#include "3rdparty/fmt/ranges.h"
extern void CheckExternalFiles();
/**
* Try to read a single piece of metadata and return false if it doesn't exist.
* Log error from reading basesets.
* @param full_filename the full filename of the loaded file
* @param detail detail log message
* @param level debug level
*/
template <class T>
void BaseSet<T>::LogError(std::string_view full_filename, std::string_view detail, int level) const
{
Debug(misc, level, "Loading base {}set details failed: {}", BaseSet<T>::SET_TYPE, full_filename);
Debug(misc, level, " {}", detail);
}
/**
* Try to read a single piece of metadata and return nullptr if it doesn't exist.
* Log error, if the data is missing.
* @param full_filename the full filename of the loaded file (for error reporting purposes)
* @param group ini group to read from
* @param name the name of the item to fetch.
*/
#define fetch_metadata(name) \
item = metadata->GetItem(name); \
if (item == nullptr || !item->value.has_value() || item->value->empty()) { \
Debug(grf, 0, "Base {}set detail loading: {} field missing.", BaseSet::SET_TYPE, name); \
Debug(grf, 0, " Is {} readable for the user running OpenTTD?", full_filename); \
return false; \
}
template <class T>
const IniItem *BaseSet<T>::GetMandatoryItem(std::string_view full_filename, const IniGroup &group, std::string_view name) const
{
auto *item = group.GetItem(name);
if (item != nullptr && item->value.has_value() && !item->value->empty()) return item;
this->LogError(full_filename, fmt::format("{}.{} field missing.", group.name, name));
return nullptr;
}
/**
* Read the set information from a loaded ini.
@ -42,16 +61,17 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
{
const IniGroup *metadata = ini.GetGroup("metadata");
if (metadata == nullptr) {
Debug(grf, 0, "Base {}set detail loading: metadata missing.", BaseSet<T>::SET_TYPE);
Debug(grf, 0, " Is {} readable for the user running OpenTTD?", full_filename);
this->LogError(full_filename, "Is the file readable for the user running OpenTTD?");
return false;
}
const IniItem *item;
fetch_metadata("name");
item = this->GetMandatoryItem(full_filename, *metadata, "name");
if (item == nullptr) return false;
this->name = *item->value;
fetch_metadata("description");
item = this->GetMandatoryItem(full_filename, *metadata, "description");
if (item == nullptr) return false;
this->description[std::string{}] = *item->value;
item = metadata->GetItem("url");
@ -64,13 +84,24 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
this->description[titem.name.substr(12)] = titem.value.value_or("");
}
fetch_metadata("shortname");
item = this->GetMandatoryItem(full_filename, *metadata, "shortname");
if (item == nullptr) return false;
for (uint i = 0; (*item->value)[i] != '\0' && i < 4; i++) {
this->shortname |= ((uint8_t)(*item->value)[i]) << (i * 8);
}
fetch_metadata("version");
this->version = atoi(item->value->c_str());
item = this->GetMandatoryItem(full_filename, *metadata, "version");
if (item == nullptr) return false;
for (StringConsumer consumer{*item->value};;) {
auto value = consumer.TryReadIntegerBase<uint32_t>(10);
bool valid = value.has_value();
if (valid) this->version.push_back(*value);
if (valid && !consumer.AnyBytesLeft()) break;
if (!valid || !consumer.ReadIf(".")) {
this->LogError(full_filename, fmt::format("metadata.version field is invalid: {}", *item->value));
return false;
}
}
item = metadata->GetItem("fallback");
this->fallback = (item != nullptr && item->value && *item->value != "0" && *item->value != "false");
@ -80,13 +111,18 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
const IniGroup *md5s = ini.GetGroup("md5s");
const IniGroup *origin = ini.GetGroup("origin");
auto file_names = BaseSet<T>::GetFilenames();
bool original_set =
std::byteswap(this->shortname) == 'TTDD' || // TTD DOS graphics, TTD DOS music
std::byteswap(this->shortname) == 'TTDW' || // TTD WIN graphics, TTD WIN music
std::byteswap(this->shortname) == 'TTDO' || // TTD sound
std::byteswap(this->shortname) == 'TTOD'; // TTO music
for (uint i = 0; i < BaseSet<T>::NUM_FILES; i++) {
MD5File *file = &this->files[i];
/* Find the filename first. */
item = files != nullptr ? files->GetItem(file_names[i]) : nullptr;
if (item == nullptr || (!item->value.has_value() && !allow_empty_filename)) {
Debug(grf, 0, "No {} file for: {} (in {})", BaseSet<T>::SET_TYPE, file_names[i], full_filename);
this->LogError(full_filename, fmt::format("files.{} field missing", file_names[i]));
return false;
}
@ -104,34 +140,19 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
/* Then find the MD5 checksum */
item = md5s != nullptr ? md5s->GetItem(filename) : nullptr;
if (item == nullptr || !item->value.has_value()) {
Debug(grf, 0, "No MD5 checksum specified for: {} (in {})", filename, full_filename);
this->LogError(full_filename, fmt::format("md5s.{} field missing", filename));
return false;
}
const char *c = item->value->c_str();
for (size_t i = 0; i < file->hash.size() * 2; i++, c++) {
uint j;
if ('0' <= *c && *c <= '9') {
j = *c - '0';
} else if ('a' <= *c && *c <= 'f') {
j = *c - 'a' + 10;
} else if ('A' <= *c && *c <= 'F') {
j = *c - 'A' + 10;
} else {
Debug(grf, 0, "Malformed MD5 checksum specified for: {} (in {})", filename, full_filename);
return false;
}
if (i % 2 == 0) {
file->hash[i / 2] = j << 4;
} else {
file->hash[i / 2] |= j;
}
if (!ConvertHexToBytes(*item->value, file->hash)) {
this->LogError(full_filename, fmt::format("md5s.{} is malformed: {}", filename, *item->value));
return false;
}
/* Then find the warning message when the file's missing */
item = origin != nullptr ? origin->GetItem(filename) : nullptr;
if (item == nullptr) item = origin != nullptr ? origin->GetItem("default") : nullptr;
if (item == nullptr || !item->value.has_value()) {
Debug(grf, 1, "No origin warning message specified for: {}", filename);
this->LogError(full_filename, fmt::format("origin.{} field missing", filename), 1);
file->missing_warning.clear();
} else {
file->missing_warning = item->value.value();
@ -148,12 +169,14 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
break;
case MD5File::CR_MISMATCH:
Debug(grf, 1, "MD5 checksum mismatch for: {} (in {})", filename, full_filename);
/* This is normal for original sample.cat, which either matches with orig_dos or orig_win. */
this->LogError(full_filename, fmt::format("MD5 checksum mismatch for: {}", filename), original_set ? 1 : 0);
this->found_files++;
break;
case MD5File::CR_NO_FILE:
Debug(grf, 1, "The file {} specified in {} is missing", filename, full_filename);
/* Missing files is normal for the original basesets. Use lower debug level */
this->LogError(full_filename, fmt::format("File is missing: {}", filename), original_set ? 1 : 0);
break;
}
}
@ -164,10 +187,9 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
template <class Tbase_set>
bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_length, const std::string &)
{
bool ret = false;
Debug(grf, 1, "Checking {} for base {} set", filename, BaseSet<Tbase_set>::SET_TYPE);
Debug(misc, 1, "Checking {} for base {} set", filename, BaseSet<Tbase_set>::SET_TYPE);
Tbase_set *set = new Tbase_set();
auto set = std::make_unique<Tbase_set>();
IniFile ini{};
std::string path{ filename, basepath_length };
ini.LoadFromDisk(path, BASESET_DIR);
@ -179,60 +201,44 @@ bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_
path.clear();
}
if (set->FillSetDetails(ini, path, filename)) {
Tbase_set *duplicate = nullptr;
for (Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != nullptr; c = c->next) {
if (c->name == set->name || c->shortname == set->shortname) {
duplicate = c;
break;
}
if (!set->FillSetDetails(ini, path, filename)) return false;
auto existing = std::ranges::find_if(BaseMedia<Tbase_set>::available_sets, [&set](const auto &c) { return c->name == set->name || c->shortname == set->shortname; });
if (existing != std::end(BaseMedia<Tbase_set>::available_sets)) {
/* The more complete set takes precedence over the version number. */
if (((*existing)->valid_files == set->valid_files && (*existing)->version >= set->version) ||
(*existing)->valid_files > set->valid_files) {
Debug(misc, 1, "Not adding {} ({}) as base {} set (duplicate, {})", set->name, fmt::join(set->version, "."),
BaseSet<Tbase_set>::SET_TYPE,
(*existing)->valid_files > set->valid_files ? "fewer valid files" : "lower version");
duplicate_sets.push_back(std::move(set));
return false;
}
if (duplicate != nullptr) {
/* The more complete set takes precedence over the version number. */
if ((duplicate->valid_files == set->valid_files && duplicate->version >= set->version) ||
duplicate->valid_files > set->valid_files) {
Debug(grf, 1, "Not adding {} ({}) as base {} set (duplicate, {})", set->name, set->version,
BaseSet<Tbase_set>::SET_TYPE,
duplicate->valid_files > set->valid_files ? "less valid files" : "lower version");
set->next = BaseMedia<Tbase_set>::duplicate_sets;
BaseMedia<Tbase_set>::duplicate_sets = set;
} else {
Tbase_set **prev = &BaseMedia<Tbase_set>::available_sets;
while (*prev != duplicate) prev = &(*prev)->next;
*prev = set;
set->next = duplicate->next;
/* If the duplicate set is currently used (due to rescanning this can happen)
* update the currently used set to the new one. This will 'lie' about the
* version number until a new game is started which isn't a big problem */
if (BaseMedia<Tbase_set>::used_set == existing->get()) BaseMedia<Tbase_set>::used_set = set.get();
/* Keep baseset configuration, if compatible */
set->CopyCompatibleConfig(*duplicate);
/* Keep baseset configuration, if compatible */
set->CopyCompatibleConfig(**existing);
/* If the duplicate set is currently used (due to rescanning this can happen)
* update the currently used set to the new one. This will 'lie' about the
* version number until a new game is started which isn't a big problem */
if (BaseMedia<Tbase_set>::used_set == duplicate) BaseMedia<Tbase_set>::used_set = set;
Debug(misc, 1, "Removing {} ({}) as base {} set (duplicate, {})", (*existing)->name, fmt::join((*existing)->version, "."), BaseSet<Tbase_set>::SET_TYPE,
(*existing)->valid_files < set->valid_files ? "fewer valid files" : "lower version");
Debug(grf, 1, "Removing {} ({}) as base {} set (duplicate, {})", duplicate->name, duplicate->version,
BaseSet<Tbase_set>::SET_TYPE,
duplicate->valid_files < set->valid_files ? "less valid files" : "lower version");
duplicate->next = BaseMedia<Tbase_set>::duplicate_sets;
BaseMedia<Tbase_set>::duplicate_sets = duplicate;
ret = true;
}
} else {
Tbase_set **last = &BaseMedia<Tbase_set>::available_sets;
while (*last != nullptr) last = &(*last)->next;
/* Existing set is worse, move it to duplicates and replace with the current set. */
duplicate_sets.push_back(std::move(*existing));
*last = set;
ret = true;
}
if (ret) {
Debug(grf, 1, "Adding {} ({}) as base {} set", set->name, set->version, BaseSet<Tbase_set>::SET_TYPE);
}
Debug(misc, 1, "Adding {} ({}) as base {} set", set->name, fmt::join(set->version, "."), BaseSet<Tbase_set>::SET_TYPE);
*existing = std::move(set);
} else {
delete set;
Debug(grf, 1, "Adding {} ({}) as base {} set", set->name, set->version, BaseSet<Tbase_set>::SET_TYPE);
available_sets.push_back(std::move(set));
}
return ret;
return true;
}
/**
@ -264,9 +270,9 @@ template <class Tbase_set>
return SetSet(nullptr);
}
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != nullptr; s = s->next) {
for (const auto &s : BaseMedia<Tbase_set>::available_sets) {
if (name == s->name) {
return SetSet(s);
return SetSet(s.get());
}
}
return false;
@ -284,9 +290,9 @@ template <class Tbase_set>
return SetSet(nullptr);
}
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != nullptr; s = s->next) {
for (const auto &s : BaseMedia<Tbase_set>::available_sets) {
if (shortname == s->shortname) {
return SetSet(s);
return SetSet(s.get());
}
}
return false;
@ -300,7 +306,7 @@ template <class Tbase_set>
/* static */ void BaseMedia<Tbase_set>::GetSetsList(std::back_insert_iterator<std::string> &output_iterator)
{
fmt::format_to(output_iterator, "List of {} sets:\n", BaseSet<Tbase_set>::SET_TYPE);
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != nullptr; s = s->next) {
for (const auto &s : BaseMedia<Tbase_set>::available_sets) {
fmt::format_to(output_iterator, "{:>18}: {}", s->name, s->GetDescription({}));
int invalid = s->GetNumInvalid();
if (invalid != 0) {
@ -319,28 +325,28 @@ template <class Tbase_set>
#include "network/core/tcp_content_type.h"
template <class Tbase_set> const char *TryGetBaseSetFile(const ContentInfo &ci, bool md5sum, const Tbase_set *s)
template <class Tbase_set> std::optional<std::string_view> TryGetBaseSetFile(const ContentInfo &ci, bool md5sum, std::span<const std::unique_ptr<Tbase_set>> sets)
{
for (; s != nullptr; s = s->next) {
for (const auto &s : sets) {
if (s->GetNumMissing() != 0) continue;
if (s->shortname != ci.unique_id) continue;
if (!md5sum) return s->files[0].filename.c_str();
if (!md5sum) return s->files[0].filename;
MD5Hash md5;
for (const auto &file : s->files) {
md5 ^= file.hash;
}
if (md5 == ci.md5sum) return s->files[0].filename.c_str();
if (md5 == ci.md5sum) return s->files[0].filename;
}
return nullptr;
return std::nullopt;
}
template <class Tbase_set>
/* static */ bool BaseMedia<Tbase_set>::HasSet(const ContentInfo &ci, bool md5sum)
{
return (TryGetBaseSetFile(ci, md5sum, BaseMedia<Tbase_set>::available_sets) != nullptr) ||
(TryGetBaseSetFile(ci, md5sum, BaseMedia<Tbase_set>::duplicate_sets) != nullptr);
return TryGetBaseSetFile(ci, md5sum, BaseMedia<Tbase_set>::GetAvailableSets()).has_value() ||
TryGetBaseSetFile(ci, md5sum, BaseMedia<Tbase_set>::GetDuplicateSets()).has_value();
}
/**
@ -350,12 +356,9 @@ template <class Tbase_set>
template <class Tbase_set>
/* static */ int BaseMedia<Tbase_set>::GetNumSets()
{
int n = 0;
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != nullptr; s = s->next) {
if (s != BaseMedia<Tbase_set>::used_set && s->GetNumMissing() != 0) continue;
n++;
}
return n;
return std::ranges::count_if(BaseMedia<Tbase_set>::GetAvailableSets(), [](const auto &set) {
return set.get() == BaseMedia<Tbase_set>::used_set || set->GetNumMissing() == 0;
});
}
/**
@ -366,8 +369,8 @@ template <class Tbase_set>
/* static */ int BaseMedia<Tbase_set>::GetIndexOfUsedSet()
{
int n = 0;
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != nullptr; s = s->next) {
if (s == BaseMedia<Tbase_set>::used_set) return n;
for (const auto &s : BaseMedia<Tbase_set>::available_sets) {
if (s.get() == BaseMedia<Tbase_set>::used_set) return n;
if (s->GetNumMissing() != 0) continue;
n++;
}
@ -381,9 +384,9 @@ template <class Tbase_set>
template <class Tbase_set>
/* static */ const Tbase_set *BaseMedia<Tbase_set>::GetSet(int index)
{
for (const Tbase_set *s = BaseMedia<Tbase_set>::available_sets; s != nullptr; s = s->next) {
if (s != BaseMedia<Tbase_set>::used_set && s->GetNumMissing() != 0) continue;
if (index == 0) return s;
for (const auto &s : BaseMedia<Tbase_set>::available_sets) {
if (s.get() != BaseMedia<Tbase_set>::used_set && s->GetNumMissing() != 0) continue;
if (index == 0) return s.get();
index--;
}
FatalError("Base{}::GetSet(): index {} out of range", BaseSet<Tbase_set>::SET_TYPE, index);
@ -398,13 +401,3 @@ template <class Tbase_set>
{
return BaseMedia<Tbase_set>::used_set;
}
/**
* Return the available sets.
* @return The available sets.
*/
template <class Tbase_set>
/* static */ Tbase_set *BaseMedia<Tbase_set>::GetAvailableSets()
{
return BaseMedia<Tbase_set>::available_sets;
}

View File

@ -74,9 +74,9 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> {
TimerGameCalendar::Date build_date{}; ///< Date of construction
uint16_t random_bits = 0; ///< Random bits assigned to this station
uint8_t waiting_triggers = 0; ///< Waiting triggers (NewGRF) for this station
uint8_t cached_anim_triggers = 0; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
uint8_t cached_roadstop_anim_triggers = 0; ///< NOSAVE: Combined animation trigger bitmask for road stops, used to determine if trigger processing should happen.
StationRandomTriggers waiting_random_triggers; ///< Waiting triggers (NewGRF), shared by all station parts/tiles, road stops, ... essentially useless and broken by design.
StationAnimationTriggers cached_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen.
StationAnimationTriggers cached_roadstop_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask for road stops, used to determine if trigger processing should happen.
CargoTypes cached_cargo_triggers{}; ///< NOSAVE: Combined cargo trigger bitmask
CargoTypes cached_roadstop_cargo_triggers{}; ///< NOSAVE: Combined cargo trigger bitmask for road stops

View File

@ -25,8 +25,8 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
{
const SpriteData *src = (const SpriteData *)bp->sprite;
const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
const uint16_t *src_n = (const uint16_t *)(src->data + src->offset[zoom][1]);
const Colour *src_px = reinterpret_cast<const Colour *>(src->data + src->offset[0][zoom]);
const uint16_t *src_n = reinterpret_cast<const uint16_t *>(src->data + src->offset[1][zoom]);
for (uint i = bp->skip_top; i != 0; i--) {
src_px = (const Colour *)((const uint8_t *)src_px + *(const uint32_t *)src_px);
@ -389,11 +389,11 @@ void Blitter_32bppAnim::CopyFromBuffer(void *video, const void *src, int width,
Colour *dst_pal = dst;
uint16_t *anim_pal = anim_line;
memcpy(static_cast<void *>(dst), usrc, width * sizeof(uint32_t));
std::copy_n(usrc, width, reinterpret_cast<uint32_t *>(dst));
usrc += width;
dst += _screen.pitch;
/* Copy back the anim-buffer */
memcpy(anim_line, usrc, width * sizeof(uint16_t));
std::copy_n(reinterpret_cast<const uint16_t *>(usrc), width, anim_line);
usrc = (const uint32_t *)&((const uint16_t *)usrc)[width];
anim_line += this->anim_buf_pitch;
@ -428,11 +428,11 @@ void Blitter_32bppAnim::CopyToBuffer(const void *video, void *dst, int width, in
const uint16_t *anim_line = this->ScreenToAnimOffset((const uint32_t *)video) + this->anim_buf;
for (; height > 0; height--) {
memcpy(udst, src, width * sizeof(uint32_t));
std::copy_n(src, width, udst);
src += _screen.pitch;
udst += width;
/* Copy the anim-buffer */
memcpy(udst, anim_line, width * sizeof(uint16_t));
std::copy_n(anim_line, width, reinterpret_cast<uint16_t *>(udst));
udst = (uint32_t *)&((uint16_t *)udst)[width];
anim_line += this->anim_buf_pitch;
}
@ -458,11 +458,7 @@ void Blitter_32bppAnim::ScrollBuffer(void *video, int &left, int &top, int &widt
uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x);
uint th = height - scroll_y;
for (; th > 0; th--) {
memcpy(dst, src, tw * sizeof(uint16_t));
src -= this->anim_buf_pitch;
dst -= this->anim_buf_pitch;
}
Blitter::MovePixels(src, dst, tw, th, -this->anim_buf_pitch);
} else {
/* Calculate pointers */
dst = this->anim_buf + left + top * this->anim_buf_pitch;
@ -475,15 +471,9 @@ void Blitter_32bppAnim::ScrollBuffer(void *video, int &left, int &top, int &widt
src -= scroll_x;
}
/* the y-displacement may be 0 therefore we have to use memmove,
* because source and destination may overlap */
uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x);
uint th = height + scroll_y;
for (; th > 0; th--) {
memmove(dst, src, tw * sizeof(uint16_t));
src += this->anim_buf_pitch;
dst += this->anim_buf_pitch;
}
Blitter::MovePixels(src, dst, tw, th, this->anim_buf_pitch);
}
Blitter_32bppBase::ScrollBuffer(video, left, top, width, height, scroll_x, scroll_y);

View File

@ -190,8 +190,8 @@ bmno_full_transparency:
const uint m1 = (uint8_t) (mvX2 >> 16);
const uint r1 = remap[m1];
if (mvX2 & 0x00FF00FF) {
/* Written so the compiler uses CMOV. */
#define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \
/* Written so the compiler uses CMOV. */ \
Colour m_colour = m_colour_init; \
{ \
const Colour srcm = (Colour) (m_src); \

View File

@ -39,8 +39,10 @@ public:
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent, bool animated>
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
Sprite *Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override {
return Blitter_32bppSSE_Base::Encode(sprite, allocator);
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override
{
return Blitter_32bppSSE_Base::Encode(sprite_type, sprite, allocator);
}
std::string_view GetName() override { return "32bpp-sse4-anim"; }
using Blitter_32bppSSE2_Anim::LookupColourInPalette;

View File

@ -51,7 +51,7 @@ void Blitter_32bppBase::CopyFromBuffer(void *video, const void *src, int width,
const uint32_t *usrc = (const uint32_t *)src;
for (; height > 0; height--) {
memcpy(dst, usrc, width * sizeof(uint32_t));
std::copy_n(usrc, width, dst);
usrc += width;
dst += _screen.pitch;
}
@ -63,7 +63,7 @@ void Blitter_32bppBase::CopyToBuffer(const void *video, void *dst, int width, in
const uint32_t *src = (const uint32_t *)video;
for (; height > 0; height--) {
memcpy(udst, src, width * sizeof(uint32_t));
std::copy_n(src, width, udst);
src += _screen.pitch;
udst += width;
}
@ -75,7 +75,7 @@ void Blitter_32bppBase::CopyImageToBuffer(const void *video, void *dst, int widt
const uint32_t *src = (const uint32_t *)video;
for (; height > 0; height--) {
memcpy(udst, src, width * sizeof(uint32_t));
std::copy_n(src, width, udst);
src += _screen.pitch;
udst += dst_pitch;
}
@ -106,11 +106,7 @@ void Blitter_32bppBase::ScrollBuffer(void *video, int &left, int &top, int &widt
width += scroll_x;
}
for (int h = height; h > 0; h--) {
memcpy(dst, src, width * sizeof(uint32_t));
src -= _screen.pitch;
dst -= _screen.pitch;
}
Blitter::MovePixels(src, dst, width, height, -_screen.pitch);
} else {
/* Calculate pointers */
dst = (uint32_t *)video + left + top * _screen.pitch;
@ -130,13 +126,7 @@ void Blitter_32bppBase::ScrollBuffer(void *video, int &left, int &top, int &widt
width += scroll_x;
}
/* the y-displacement may be 0 therefore we have to use memmove,
* because source and destination may overlap */
for (int h = height; h > 0; h--) {
memmove(dst, src, width * sizeof(uint32_t));
src += _screen.pitch;
dst += _screen.pitch;
}
Blitter::MovePixels(src, dst, width, height, _screen.pitch);
}
}

View File

@ -32,11 +32,11 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL
/* src_px : each line begins with uint32_t n = 'number of bytes in this line',
* then n times is the Colour struct for this line */
const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
const Colour *src_px = reinterpret_cast<const Colour *>(src->data + src->offset[0][zoom]);
/* src_n : each line begins with uint32_t n = 'number of bytes in this line',
* then interleaved stream of 'm' and 'n' channels. 'm' is remap,
* 'n' is number of bytes with the same alpha channel class */
const uint16_t *src_n = (const uint16_t *)(src->data + src->offset[zoom][1]);
const uint16_t *src_n = reinterpret_cast<const uint16_t *>(src->data + src->offset[1][zoom]);
/* skip upper lines in src_px and src_n */
for (uint i = bp->skip_top; i != 0; i--) {
@ -285,12 +285,13 @@ void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode,
this->Draw<false>(bp, mode, zoom);
}
template <bool Tpal_to_rgb> Sprite *Blitter_32bppOptimized::EncodeInternal(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
template <bool Tpal_to_rgb>
Sprite *Blitter_32bppOptimized::EncodeInternal(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
{
/* streams of pixels (a, r, g, b channels)
*
* stored in separated stream so data are always aligned on 4B boundary */
std::array<std::unique_ptr<Colour[]>, ZOOM_LVL_END> dst_px_orig;
SpriteCollMap<std::unique_ptr<Colour[]>> dst_px_orig;
/* interleaved stream of 'm' channel and 'n' channel
* 'n' is number of following pixels with the same alpha channel class
@ -298,21 +299,21 @@ template <bool Tpal_to_rgb> Sprite *Blitter_32bppOptimized::EncodeInternal(const
*
* it has to be stored in one stream so fewer registers are used -
* x86 has problems with register allocation even with this solution */
std::array<std::unique_ptr<uint16_t[]>, ZOOM_LVL_END> dst_n_orig;
SpriteCollMap<std::unique_ptr<uint16_t[]>> dst_n_orig;
/* lengths of streams */
uint32_t lengths[ZOOM_LVL_END][2];
SpriteCollMap<uint32_t> lengths[2];
ZoomLevel zoom_min;
ZoomLevel zoom_max;
if (sprite[ZOOM_LVL_MIN].type == SpriteType::Font) {
zoom_min = ZOOM_LVL_MIN;
zoom_max = ZOOM_LVL_MIN;
if (sprite_type == SpriteType::Font) {
zoom_min = ZoomLevel::Min;
zoom_max = ZoomLevel::Min;
} else {
zoom_min = _settings_client.gui.zoom_min;
zoom_max = _settings_client.gui.zoom_max;
if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX;
if (zoom_max == zoom_min) zoom_max = ZoomLevel::Max;
}
for (ZoomLevel z = zoom_min; z <= zoom_max; z++) {
@ -405,40 +406,43 @@ template <bool Tpal_to_rgb> Sprite *Blitter_32bppOptimized::EncodeInternal(const
dst_n_ln = (uint32_t *)dst_n;
}
lengths[z][0] = reinterpret_cast<uint8_t *>(dst_px_ln) - reinterpret_cast<uint8_t *>(dst_px_orig[z].get()); // all are aligned to 4B boundary
lengths[z][1] = reinterpret_cast<uint8_t *>(dst_n_ln) - reinterpret_cast<uint8_t *>(dst_n_orig[z].get());
lengths[0][z] = reinterpret_cast<uint8_t *>(dst_px_ln) - reinterpret_cast<uint8_t *>(dst_px_orig[z].get()); // all are aligned to 4B boundary
lengths[1][z] = reinterpret_cast<uint8_t *>(dst_n_ln) - reinterpret_cast<uint8_t *>(dst_n_orig[z].get());
}
uint len = 0; // total length of data
for (ZoomLevel z = zoom_min; z <= zoom_max; z++) {
len += lengths[z][0] + lengths[z][1];
len += lengths[0][z] + lengths[1][z];
}
Sprite *dest_sprite = allocator.Allocate<Sprite>(sizeof(*dest_sprite) + sizeof(SpriteData) + len);
dest_sprite->height = sprite[ZOOM_LVL_MIN].height;
dest_sprite->width = sprite[ZOOM_LVL_MIN].width;
dest_sprite->x_offs = sprite[ZOOM_LVL_MIN].x_offs;
dest_sprite->y_offs = sprite[ZOOM_LVL_MIN].y_offs;
const auto &root_sprite = sprite.Root();
dest_sprite->height = root_sprite.height;
dest_sprite->width = root_sprite.width;
dest_sprite->x_offs = root_sprite.x_offs;
dest_sprite->y_offs = root_sprite.y_offs;
SpriteData *dst = (SpriteData *)dest_sprite->data;
memset(dst, 0, sizeof(*dst));
uint32_t offset = 0;
for (ZoomLevel z = zoom_min; z <= zoom_max; z++) {
dst->offset[z][0] = z == zoom_min ? 0 : lengths[z - 1][1] + dst->offset[z - 1][1];
dst->offset[z][1] = lengths[z][0] + dst->offset[z][0];
dst->offset[0][z] = offset;
offset += lengths[0][z];
dst->offset[1][z] = offset;
offset += lengths[1][z];
memcpy(dst->data + dst->offset[z][0], dst_px_orig[z].get(), lengths[z][0]);
memcpy(dst->data + dst->offset[z][1], dst_n_orig[z].get(), lengths[z][1]);
std::copy_n(reinterpret_cast<uint8_t *>(dst_px_orig[z].get()), lengths[0][z], dst->data + dst->offset[0][z]);
std::copy_n(reinterpret_cast<uint8_t *>(dst_n_orig[z].get()), lengths[1][z], dst->data + dst->offset[1][z]);
}
return dest_sprite;
}
template Sprite *Blitter_32bppOptimized::EncodeInternal<true>(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator);
template Sprite *Blitter_32bppOptimized::EncodeInternal<false>(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator);
template Sprite *Blitter_32bppOptimized::EncodeInternal<true>(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator);
template Sprite *Blitter_32bppOptimized::EncodeInternal<false>(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator);
Sprite *Blitter_32bppOptimized::Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
Sprite *Blitter_32bppOptimized::Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
{
return this->EncodeInternal<true>(sprite, allocator);
return this->EncodeInternal<true>(sprite_type, sprite, allocator);
}

View File

@ -17,12 +17,12 @@ class Blitter_32bppOptimized : public Blitter_32bppSimple {
public:
/** Data stored about a (single) sprite. */
struct SpriteData {
uint32_t offset[ZOOM_LVL_END][2]; ///< Offsets (from .data) to streams for different zoom levels, and the normal and remap image information.
SpriteCollMap<uint32_t> offset[2]; ///< Offsets (from .data) to streams for different zoom levels, and the normal and remap image information.
uint8_t data[]; ///< Data, all zoomlevels.
};
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
Sprite *Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
std::string_view GetName() override { return "32bpp-optimized"; }
@ -30,7 +30,7 @@ public:
protected:
template <bool Tpal_to_rgb> void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
template <bool Tpal_to_rgb> Sprite *EncodeInternal(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator);
template <bool Tpal_to_rgb> Sprite *EncodeInternal(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator);
};
/** Factory for the optimised 32 bpp blitter (without palette animation). */

View File

@ -115,20 +115,21 @@ void Blitter_32bppSimple::DrawColourMappingRect(void *dst, int width, int height
Debug(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('{}')", pal);
}
Sprite *Blitter_32bppSimple::Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
Sprite *Blitter_32bppSimple::Encode(SpriteType, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
{
const auto &root_sprite = sprite.Root();
Blitter_32bppSimple::Pixel *dst;
Sprite *dest_sprite = allocator.Allocate<Sprite>(sizeof(*dest_sprite) + static_cast<size_t>(sprite[ZOOM_LVL_MIN].height) * static_cast<size_t>(sprite[ZOOM_LVL_MIN].width) * sizeof(*dst));
Sprite *dest_sprite = allocator.Allocate<Sprite>(sizeof(*dest_sprite) + static_cast<size_t>(root_sprite.height) * static_cast<size_t>(root_sprite.width) * sizeof(*dst));
dest_sprite->height = sprite[ZOOM_LVL_MIN].height;
dest_sprite->width = sprite[ZOOM_LVL_MIN].width;
dest_sprite->x_offs = sprite[ZOOM_LVL_MIN].x_offs;
dest_sprite->y_offs = sprite[ZOOM_LVL_MIN].y_offs;
dest_sprite->height = root_sprite.height;
dest_sprite->width = root_sprite.width;
dest_sprite->x_offs = root_sprite.x_offs;
dest_sprite->y_offs = root_sprite.y_offs;
dst = (Blitter_32bppSimple::Pixel *)dest_sprite->data;
SpriteLoader::CommonPixel *src = (SpriteLoader::CommonPixel *)sprite[ZOOM_LVL_MIN].data;
dst = reinterpret_cast<Blitter_32bppSimple::Pixel *>(dest_sprite->data);
SpriteLoader::CommonPixel *src = reinterpret_cast<SpriteLoader::CommonPixel *>(root_sprite.data);
for (int i = 0; i < sprite[ZOOM_LVL_MIN].height * sprite[ZOOM_LVL_MIN].width; i++) {
for (int i = 0; i < root_sprite.height * root_sprite.width; i++) {
if (src->m == 0) {
dst[i].r = src->r;
dst[i].g = src->g;

View File

@ -26,7 +26,7 @@ class Blitter_32bppSimple : public Blitter_32bppBase {
public:
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
Sprite *Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
std::string_view GetName() override { return "32bpp-simple"; }
};

View File

@ -20,18 +20,18 @@
/** Instantiation of the SSE2 32bpp blitter factory. */
static FBlitter_32bppSSE2 iFBlitter_32bppSSE2;
Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
Sprite *Blitter_32bppSSE_Base::Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
{
/* First uint32_t of a line = the number of transparent pixels from the left.
* Second uint32_t of a line = the number of transparent pixels from the right.
* Then all RGBA then all MV.
*/
ZoomLevel zoom_min = ZOOM_LVL_MIN;
ZoomLevel zoom_max = ZOOM_LVL_MIN;
if (sprite[ZOOM_LVL_MIN].type != SpriteType::Font) {
ZoomLevel zoom_min = ZoomLevel::Min;
ZoomLevel zoom_max = ZoomLevel::Min;
if (sprite_type != SpriteType::Font) {
zoom_min = _settings_client.gui.zoom_min;
zoom_max = _settings_client.gui.zoom_max;
if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX;
if (zoom_max == zoom_min) zoom_max = ZoomLevel::Max;
}
/* Calculate sizes and allocate. */
@ -39,23 +39,25 @@ Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::SpriteCollection &spri
uint all_sprites_size = 0;
for (ZoomLevel z = zoom_min; z <= zoom_max; z++) {
const SpriteLoader::Sprite *src_sprite = &sprite[z];
sd.infos[z].sprite_width = src_sprite->width;
sd.infos[z].sprite_offset = all_sprites_size;
sd.infos[z].sprite_line_size = sizeof(Colour) * src_sprite->width + sizeof(uint32_t) * META_LENGTH;
auto &info = sd.infos[z];
info.sprite_width = src_sprite->width;
info.sprite_offset = all_sprites_size;
info.sprite_line_size = sizeof(Colour) * src_sprite->width + sizeof(uint32_t) * META_LENGTH;
const uint rgba_size = sd.infos[z].sprite_line_size * src_sprite->height;
sd.infos[z].mv_offset = all_sprites_size + rgba_size;
const uint rgba_size = info.sprite_line_size * src_sprite->height;
info.mv_offset = all_sprites_size + rgba_size;
const uint mv_size = sizeof(MapValue) * src_sprite->width * src_sprite->height;
all_sprites_size += rgba_size + mv_size;
}
Sprite *dst_sprite = allocator.Allocate<Sprite>(sizeof(Sprite) + sizeof(SpriteData) + all_sprites_size);
dst_sprite->height = sprite[ZOOM_LVL_MIN].height;
dst_sprite->width = sprite[ZOOM_LVL_MIN].width;
dst_sprite->x_offs = sprite[ZOOM_LVL_MIN].x_offs;
dst_sprite->y_offs = sprite[ZOOM_LVL_MIN].y_offs;
memcpy(dst_sprite->data, &sd, sizeof(SpriteData));
const auto &root_sprite = sprite.Root();
dst_sprite->height = root_sprite.height;
dst_sprite->width = root_sprite.width;
dst_sprite->x_offs = root_sprite.x_offs;
dst_sprite->y_offs = root_sprite.y_offs;
std::copy_n(reinterpret_cast<std::byte *>(&sd), sizeof(SpriteData), dst_sprite->data);
/* Copy colours and determine flags. */
bool has_remap = false;
@ -64,8 +66,9 @@ Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::SpriteCollection &spri
for (ZoomLevel z = zoom_min; z <= zoom_max; z++) {
const SpriteLoader::Sprite *src_sprite = &sprite[z];
const SpriteLoader::CommonPixel *src = (const SpriteLoader::CommonPixel *) src_sprite->data;
Colour *dst_rgba_line = (Colour *) &dst_sprite->data[sizeof(SpriteData) + sd.infos[z].sprite_offset];
MapValue *dst_mv = (MapValue *) &dst_sprite->data[sizeof(SpriteData) + sd.infos[z].mv_offset];
const auto &info = sd.infos[z];
Colour *dst_rgba_line = reinterpret_cast<Colour *>(&dst_sprite->data[sizeof(SpriteData) + info.sprite_offset]);
MapValue *dst_mv = reinterpret_cast<MapValue *>(&dst_sprite->data[sizeof(SpriteData) + info.mv_offset]);
for (uint y = src_sprite->height; y != 0; y--) {
Colour *dst_rgba = dst_rgba_line + META_LENGTH;
for (uint x = src_sprite->width; x != 0; x--) {
@ -113,7 +116,7 @@ Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::SpriteCollection &spri
(*dst_rgba_line).data = nb_pix_transp;
Colour *nb_right = dst_rgba_line + 1;
dst_rgba_line = (Colour*) ((uint8_t*) dst_rgba_line + sd.infos[z].sprite_line_size);
dst_rgba_line = reinterpret_cast<Colour *>(reinterpret_cast<std::byte *>(dst_rgba_line) + info.sprite_line_size);
/* Count the number of transparent pixels from the right. */
dst_rgba = dst_rgba_line - 1;
@ -132,7 +135,7 @@ Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::SpriteCollection &spri
if (has_translucency) sd.flags.Set(SpriteFlag::Translucent);
if (!has_remap) sd.flags.Set(SpriteFlag::NoRemap);
if (!has_anim) sd.flags.Set(SpriteFlag::NoAnim);
memcpy(dst_sprite->data, &sd, sizeof(SpriteData));
std::copy_n(reinterpret_cast<std::byte *>(&sd), sizeof(SpriteData), dst_sprite->data);
return dst_sprite;
}

View File

@ -73,11 +73,11 @@ public:
};
struct SpriteData {
SpriteFlags flags{};
std::array<SpriteInfo, ZOOM_LVL_END> infos{};
SpriteCollMap<SpriteInfo> infos{};
uint8_t data[]; ///< Data, all zoomlevels.
};
Sprite *Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator);
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator);
};
/** The SSE2 32 bpp blitter (without palette animation). */
@ -87,8 +87,9 @@ public:
template <BlitterMode mode, Blitter_32bppSSE_Base::ReadMode read_mode, Blitter_32bppSSE_Base::BlockType bt_last, bool translucent>
void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom);
Sprite *Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override {
return Blitter_32bppSSE_Base::Encode(sprite, allocator);
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override
{
return Blitter_32bppSSE_Base::Encode(sprite_type, sprite, allocator);
}
std::string_view GetName() override { return "32bpp-sse2"; }

View File

@ -309,8 +309,8 @@ inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel
/* Remap colours. */
if (mvX2 & 0x00FF00FF) {
/* Written so the compiler uses CMOV. */
#define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \
/* Written so the compiler uses CMOV. */ \
Colour m_colour = m_colour_init; \
{ \
const Colour srcm = (Colour) (m_src); \

View File

@ -28,18 +28,10 @@
#endif
#define META_LENGTH 2 ///< Number of uint32_t inserted before each line of pixels in a sprite.
#define MARGIN_NORMAL_THRESHOLD (zoom == ZOOM_LVL_OUT_8X ? 8 : 4) ///< Minimum width to use margins with BlitterMode::Normal.
#define MARGIN_NORMAL_THRESHOLD (zoom == ZoomLevel::Out8x ? 8 : 4) ///< Minimum width to use margins with BlitterMode::Normal.
#define MARGIN_REMAP_THRESHOLD 4 ///< Minimum width to use margins with BlitterMode::ColourRemap.
#undef ALIGN
#ifdef _MSC_VER
#define ALIGN(n) __declspec(align(n))
#else
#define ALIGN(n) __attribute__ ((aligned (n)))
#endif
typedef union ALIGN(16) um128i {
typedef union alignas(16) um128i {
__m128i m128i;
uint8_t m128i_u8[16];
uint16_t m128i_u16[8];

View File

@ -96,11 +96,11 @@ inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
/* src_px : each line begins with uint32_t n = 'number of bytes in this line',
* then n times is the Colour struct for this line */
const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]);
const Colour *src_px = reinterpret_cast<const Colour *>(src->data + src->offset[0][zoom]);
/* src_n : each line begins with uint32_t n = 'number of bytes in this line',
* then interleaved stream of 'm' and 'n' channels. 'm' is remap,
* 'n' is number of bytes with the same alpha channel class */
const uint16_t *src_n = (const uint16_t *)(src->data + src->offset[zoom][1]);
const uint16_t *src_n = reinterpret_cast<const uint16_t *>(src->data + src->offset[1][zoom]);
/* skip upper lines in src_px and src_n */
for (uint i = bp->skip_top; i != 0; i--) {
@ -377,8 +377,11 @@ void Blitter_40bppAnim::DrawColourMappingRect(void *dst, int width, int height,
const uint8_t *remap = GetNonSprite(pal, SpriteType::Recolour) + 1;
do {
for (int i = 0; i != width; i++) {
if (*anim == 0) *udst = MakeGrey(*udst);
*anim = remap[*anim];
if (*anim == 0) {
*udst = MakeGrey(*udst);
} else {
*anim = remap[*anim];
}
udst++;
anim++;
}
@ -389,7 +392,7 @@ void Blitter_40bppAnim::DrawColourMappingRect(void *dst, int width, int height,
const uint8_t *remap = GetNonSprite(pal, SpriteType::Recolour) + 1;
do {
for (int i = 0; i != width; i++) {
*anim = remap[*anim];
if (*anim != 0) *anim = remap[*anim];
anim++;
}
anim = anim - width + _screen.pitch;
@ -397,9 +400,9 @@ void Blitter_40bppAnim::DrawColourMappingRect(void *dst, int width, int height,
}
}
Sprite *Blitter_40bppAnim::Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
Sprite *Blitter_40bppAnim::Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
{
return this->EncodeInternal<false>(sprite, allocator);
return this->EncodeInternal<false>(sprite_type, sprite, allocator);
}
@ -415,11 +418,11 @@ void Blitter_40bppAnim::CopyFromBuffer(void *video, const void *src, int width,
uint8_t *anim_line = ((uint32_t *)video - (uint32_t *)_screen.dst_ptr) + anim_buf;
for (; height > 0; height--) {
memcpy(dst, usrc, width * sizeof(uint32_t));
std::copy_n(usrc, width, dst);
usrc += width;
dst += _screen.pitch;
/* Copy back the anim-buffer */
memcpy(anim_line, usrc, width * sizeof(uint8_t));
std::copy_n(reinterpret_cast<const uint8_t *>(usrc), width, anim_line);
usrc = (const uint32_t *)((const uint8_t *)usrc + width);
anim_line += _screen.pitch;
}
@ -437,11 +440,11 @@ void Blitter_40bppAnim::CopyToBuffer(const void *video, void *dst, int width, in
const uint8_t *anim_line = ((const uint32_t *)video - (uint32_t *)_screen.dst_ptr) + anim_buf;
for (; height > 0; height--) {
memcpy(udst, src, width * sizeof(uint32_t));
std::copy_n(src, width, udst);
src += _screen.pitch;
udst += width;
/* Copy the anim-buffer */
memcpy(udst, anim_line, width * sizeof(uint8_t));
std::copy_n(anim_line, width, reinterpret_cast<uint8_t *>(udst));
udst = (uint32_t *)((uint8_t *)udst + width);
anim_line += _screen.pitch;
}
@ -490,11 +493,7 @@ void Blitter_40bppAnim::ScrollBuffer(void *video, int &left, int &top, int &widt
uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x);
uint th = height - scroll_y;
for (; th > 0; th--) {
memcpy(dst, src, tw * sizeof(uint8_t));
src -= _screen.pitch;
dst -= _screen.pitch;
}
Blitter::MovePixels(src, dst, tw, th, -_screen.pitch);
} else {
/* Calculate pointers */
dst = anim_buf + left + top * _screen.pitch;
@ -507,15 +506,9 @@ void Blitter_40bppAnim::ScrollBuffer(void *video, int &left, int &top, int &widt
src -= scroll_x;
}
/* the y-displacement may be 0 therefore we have to use memmove,
* because source and destination may overlap */
uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x);
uint th = height + scroll_y;
for (; th > 0; th--) {
memmove(dst, src, tw * sizeof(uint8_t));
src += _screen.pitch;
dst += _screen.pitch;
}
Blitter::MovePixels(src, dst, tw, th, _screen.pitch);
}
Blitter_32bppBase::ScrollBuffer(video, left, top, width, height, scroll_x, scroll_y);

View File

@ -27,7 +27,7 @@ public:
void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override;
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override;
Sprite *Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
size_t BufferSize(uint width, uint height) override;
Blitter::PaletteAnimation UsePaletteAnimation() override;
bool NeedsAnimationBuffer() override;

View File

@ -43,9 +43,10 @@ void Blitter_8bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int s
void Blitter_8bppBase::DrawRect(void *video, int width, int height, uint8_t colour)
{
std::byte *p = static_cast<std::byte *>(video);
do {
memset(video, colour, width);
video = (uint8_t *)video + _screen.pitch;
std::fill_n(p, width, static_cast<std::byte>(colour));
p += _screen.pitch;
} while (--height);
}
@ -55,7 +56,7 @@ void Blitter_8bppBase::CopyFromBuffer(void *video, const void *src, int width, i
const uint8_t *usrc = (const uint8_t *)src;
for (; height > 0; height--) {
memcpy(dst, usrc, width * sizeof(uint8_t));
std::copy_n(usrc, width, dst);
usrc += width;
dst += _screen.pitch;
}
@ -67,7 +68,7 @@ void Blitter_8bppBase::CopyToBuffer(const void *video, void *dst, int width, int
const uint8_t *src = (const uint8_t *)video;
for (; height > 0; height--) {
memcpy(udst, src, width * sizeof(uint8_t));
std::copy_n(src, width, udst);
src += _screen.pitch;
udst += width;
}
@ -79,7 +80,7 @@ void Blitter_8bppBase::CopyImageToBuffer(const void *video, void *dst, int width
const uint8_t *src = (const uint8_t *)video;
for (; height > 0; height--) {
memcpy(udst, src, width * sizeof(uint8_t));
std::copy_n(src, width, udst);
src += _screen.pitch;
udst += dst_pitch;
}
@ -110,11 +111,7 @@ void Blitter_8bppBase::ScrollBuffer(void *video, int &left, int &top, int &width
width += scroll_x;
}
for (int h = height; h > 0; h--) {
memcpy(dst, src, width * sizeof(uint8_t));
src -= _screen.pitch;
dst -= _screen.pitch;
}
Blitter::MovePixels(src, dst, width, height, -_screen.pitch);
} else {
/* Calculate pointers */
dst = (uint8_t *)video + left + top * _screen.pitch;
@ -134,13 +131,7 @@ void Blitter_8bppBase::ScrollBuffer(void *video, int &left, int &top, int &width
width += scroll_x;
}
/* the y-displacement may be 0 therefore we have to use memmove,
* because source and destination may overlap */
for (int h = height; h > 0; h--) {
memmove(dst, src, width * sizeof(uint8_t));
src += _screen.pitch;
dst += _screen.pitch;
}
Blitter::MovePixels(src, dst, width, height, _screen.pitch);
}
}

View File

@ -11,7 +11,6 @@
#include "../zoom_func.h"
#include "../settings_type.h"
#include "../core/math_func.hpp"
#include "../core/mem_func.hpp"
#include "8bpp_optimized.hpp"
#include "../safeguards.h"
@ -96,7 +95,7 @@ void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Z
}
case BlitterMode::BlackRemap:
MemSetT(dst, 0, pixels);
std::fill_n(dst, pixels, 0);
dst += pixels;
break;
@ -112,7 +111,7 @@ void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Z
}
default:
MemCpyT(dst, src, pixels);
std::copy_n(src, pixels, dst);
dst += pixels; src += pixels;
break;
}
@ -120,7 +119,7 @@ void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Z
}
}
Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
Sprite *Blitter_8bppOptimized::Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
{
/* Make memory for all zoom-levels */
uint memory = sizeof(SpriteData);
@ -128,13 +127,13 @@ Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::SpriteCollection &spri
ZoomLevel zoom_min;
ZoomLevel zoom_max;
if (sprite[ZOOM_LVL_MIN].type == SpriteType::Font) {
zoom_min = ZOOM_LVL_MIN;
zoom_max = ZOOM_LVL_MIN;
if (sprite_type == SpriteType::Font) {
zoom_min = ZoomLevel::Min;
zoom_max = ZoomLevel::Min;
} else {
zoom_min = _settings_client.gui.zoom_min;
zoom_max = _settings_client.gui.zoom_max;
if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX;
if (zoom_max == zoom_min) zoom_max = ZoomLevel::Max;
}
for (ZoomLevel i = zoom_min; i <= zoom_max; i++) {
@ -153,13 +152,14 @@ Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::SpriteCollection &spri
/* Make the sprites per zoom-level */
for (ZoomLevel i = zoom_min; i <= zoom_max; i++) {
const SpriteLoader::Sprite &src_orig = sprite[i];
/* Store the index table */
uint offset = dst - temp_dst->data;
temp_dst->offset[i] = offset;
/* cache values, because compiler can't cache it */
int scaled_height = sprite[i].height;
int scaled_width = sprite[i].width;
int scaled_height = src_orig.height;
int scaled_width = src_orig.width;
for (int y = 0; y < scaled_height; y++) {
uint trans = 0;
@ -168,7 +168,7 @@ Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::SpriteCollection &spri
uint8_t *count_dst = nullptr;
/* Store the scaled image */
const SpriteLoader::CommonPixel *src = &sprite[i].data[y * sprite[i].width];
const SpriteLoader::CommonPixel *src = &src_orig.data[y * src_orig.width];
for (int x = 0; x < scaled_width; x++) {
uint colour = src++->m;
@ -220,11 +220,12 @@ Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::SpriteCollection &spri
/* Allocate the exact amount of memory we need */
Sprite *dest_sprite = allocator.Allocate<Sprite>(sizeof(*dest_sprite) + size);
dest_sprite->height = sprite[ZOOM_LVL_MIN].height;
dest_sprite->width = sprite[ZOOM_LVL_MIN].width;
dest_sprite->x_offs = sprite[ZOOM_LVL_MIN].x_offs;
dest_sprite->y_offs = sprite[ZOOM_LVL_MIN].y_offs;
memcpy(dest_sprite->data, temp_dst, size);
const auto &root_sprite = sprite.Root();
dest_sprite->height = root_sprite.height;
dest_sprite->width = root_sprite.width;
dest_sprite->x_offs = root_sprite.x_offs;
dest_sprite->y_offs = root_sprite.y_offs;
std::copy_n(reinterpret_cast<std::byte *>(temp_dst), size, dest_sprite->data);
return dest_sprite;
}

View File

@ -18,12 +18,12 @@ class Blitter_8bppOptimized final : public Blitter_8bppBase {
public:
/** Data stored about a (single) sprite. */
struct SpriteData {
uint32_t offset[ZOOM_LVL_END]; ///< Offsets (from .data) to streams for different zoom levels.
SpriteCollMap<uint32_t> offset; ///< Offsets (from .data) to streams for different zoom levels.
uint8_t data[]; ///< Data, all zoomlevels.
};
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
Sprite *Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
std::string_view GetName() override { return "8bpp-optimized"; }
};

View File

@ -61,19 +61,21 @@ void Blitter_8bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, Zoom
}
}
Sprite *Blitter_8bppSimple::Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
Sprite *Blitter_8bppSimple::Encode(SpriteType, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
{
const auto &root_sprite = sprite.Root();
Sprite *dest_sprite;
dest_sprite = allocator.Allocate<Sprite>(sizeof(*dest_sprite) + static_cast<size_t>(sprite[ZOOM_LVL_MIN].height) * static_cast<size_t>(sprite[ZOOM_LVL_MIN].width));
dest_sprite = allocator.Allocate<Sprite>(sizeof(*dest_sprite) + static_cast<size_t>(root_sprite.height) * static_cast<size_t>(root_sprite.width));
dest_sprite->height = sprite[ZOOM_LVL_MIN].height;
dest_sprite->width = sprite[ZOOM_LVL_MIN].width;
dest_sprite->x_offs = sprite[ZOOM_LVL_MIN].x_offs;
dest_sprite->y_offs = sprite[ZOOM_LVL_MIN].y_offs;
dest_sprite->height = root_sprite.height;
dest_sprite->width = root_sprite.width;
dest_sprite->x_offs = root_sprite.x_offs;
dest_sprite->y_offs = root_sprite.y_offs;
/* Copy over only the 'remap' channel, as that is what we care about in 8bpp */
for (int i = 0; i < sprite[ZOOM_LVL_MIN].height * sprite[ZOOM_LVL_MIN].width; i++) {
dest_sprite->data[i] = sprite[ZOOM_LVL_MIN].data[i].m;
uint8_t *dst = reinterpret_cast<uint8_t *>(dest_sprite->data);
for (int i = 0; i < root_sprite.height * root_sprite.width; i++) {
dst[i] = root_sprite.data[i].m;
}
return dest_sprite;

View File

@ -17,7 +17,7 @@
class Blitter_8bppSimple final : public Blitter_8bppBase {
public:
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;
Sprite *Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
std::string_view GetName() override { return "8bpp-simple"; }
};

View File

@ -207,6 +207,8 @@ public:
virtual ~Blitter() = default;
template <typename SetPixelT> void DrawLineGeneric(int x, int y, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel);
template <typename T> static void MovePixels(const T *src, T *dst, size_t width, size_t height, ptrdiff_t pitch);
};
#endif /* BLITTER_BASE_HPP */

View File

@ -192,4 +192,24 @@ void Blitter::DrawLineGeneric(int x1, int y1, int x2, int y2, int screen_width,
}
}
template <typename T>
/* static */ void Blitter::MovePixels(const T *src, T *dst, size_t width, size_t height, ptrdiff_t pitch)
{
if (src == dst) return;
if (src < dst) {
for (size_t i = 0; i < height; ++i) {
std::move_backward(src, src + width, dst + width);
src += pitch;
dst += pitch;
}
} else {
for (size_t i = 0; i < height; ++i) {
std::move(src, src + width, dst);
src += pitch;
dst += pitch;
}
}
}
#endif /* BLITTER_COMMON_HPP */

View File

@ -55,7 +55,7 @@ protected:
* @pre description != nullptr.
* @pre There is no blitter registered with this name.
*/
BlitterFactory(const char *name, const char *description, bool usable = true) :
BlitterFactory(std::string_view name, std::string_view description, bool usable = true) :
name(name), description(description)
{
if (usable) {
@ -93,7 +93,7 @@ public:
* @param name the blitter to select.
* @post Sets the blitter so GetCurrentBlitter() returns it too.
*/
static Blitter *SelectBlitter(const std::string_view name)
static Blitter *SelectBlitter(std::string_view name)
{
BlitterFactory *b = GetBlitterFactory(name);
if (b == nullptr) return nullptr;
@ -109,17 +109,17 @@ public:
* @param name the blitter factory to select.
* @return The blitter factory, or nullptr when there isn't one with the wanted name.
*/
static BlitterFactory *GetBlitterFactory(const std::string_view name)
static BlitterFactory *GetBlitterFactory(std::string_view name)
{
#if defined(DEDICATED)
const std::string_view default_blitter = "null";
static const std::string_view default_blitter = "null";
#elif defined(WITH_COCOA)
const std::string_view default_blitter = "32bpp-anim";
static const std::string_view default_blitter = "32bpp-anim";
#else
const std::string_view default_blitter = "8bpp-optimized";
static const std::string_view default_blitter = "8bpp-optimized";
#endif
if (GetBlitters().empty()) return nullptr;
const std::string_view bname = name.empty() ? default_blitter : name;
std::string_view bname = name.empty() ? default_blitter : name;
for (auto &it : GetBlitters()) {
BlitterFactory *b = it.second;

View File

@ -15,15 +15,16 @@
/** Instantiation of the null blitter factory. */
static FBlitter_Null iFBlitter_Null;
Sprite *Blitter_Null::Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
Sprite *Blitter_Null::Encode(SpriteType, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)
{
Sprite *dest_sprite;
dest_sprite = allocator.Allocate<Sprite>(sizeof(*dest_sprite));
dest_sprite->height = sprite[ZOOM_LVL_MIN].height;
dest_sprite->width = sprite[ZOOM_LVL_MIN].width;
dest_sprite->x_offs = sprite[ZOOM_LVL_MIN].x_offs;
dest_sprite->y_offs = sprite[ZOOM_LVL_MIN].y_offs;
const auto &root_sprite = sprite.Root();
dest_sprite->height = root_sprite.height;
dest_sprite->width = root_sprite.width;
dest_sprite->x_offs = root_sprite.x_offs;
dest_sprite->y_offs = root_sprite.y_offs;
return dest_sprite;
}

View File

@ -18,7 +18,7 @@ public:
uint8_t GetScreenDepth() override { return 0; }
void Draw(Blitter::BlitterParams *, BlitterMode, ZoomLevel) override {};
void DrawColourMappingRect(void *, int, int, PaletteID) override {};
Sprite *Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
Sprite *Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override;
void *MoveTo(void *, int, int) override { return nullptr; };
void SetPixel(void *, int, int, uint8_t) override {};
void DrawRect(void *, int, int, uint8_t) override {};

View File

@ -42,7 +42,7 @@ static constexpr NWidgetPart _background_widgets[] = {
* Window description for the background window to prevent smearing.
*/
static WindowDesc _background_desc(
WDP_MANUAL, nullptr, 0, 0,
WDP_MANUAL, {}, 0, 0,
WC_BOOTSTRAP, WC_NONE,
WindowDefaultFlag::NoClose,
_background_widgets
@ -78,7 +78,7 @@ static constexpr NWidgetPart _nested_bootstrap_errmsg_widgets[] = {
/** Window description for the error window. */
static WindowDesc _bootstrap_errmsg_desc(
WDP_CENTER, nullptr, 0, 0,
WDP_CENTER, {}, 0, 0,
WC_BOOTSTRAP, WC_NONE,
{WindowDefaultFlag::Modal, WindowDefaultFlag::NoClose},
_nested_bootstrap_errmsg_widgets
@ -135,7 +135,7 @@ static constexpr NWidgetPart _nested_bootstrap_download_status_window_widgets[]
/** Window description for the download window */
static WindowDesc _bootstrap_download_status_window_desc(
WDP_CENTER, nullptr, 0, 0,
WDP_CENTER, {}, 0, 0,
WC_NETWORK_STATUS_WINDOW, WC_NONE,
{WindowDefaultFlag::Modal, WindowDefaultFlag::NoClose},
_nested_bootstrap_download_status_window_widgets
@ -187,7 +187,7 @@ static constexpr NWidgetPart _bootstrap_query_widgets[] = {
/** The window description for the query. */
static WindowDesc _bootstrap_query_desc(
WDP_CENTER, nullptr, 0, 0,
WDP_CENTER, {}, 0, 0,
WC_CONFIRM_POPUP_QUERY, WC_NONE,
WindowDefaultFlag::NoClose,
_bootstrap_query_widgets

View File

@ -205,7 +205,7 @@ public:
sprite_dim = maxdim(sprite_dim, GetScaledSpriteSize(bridge_data.spec->sprite));
text_dim = maxdim(text_dim, GetStringBoundingBox(GetBridgeSelectString(bridge_data)));
}
resize.height = std::max(sprite_dim.height, text_dim.height) + padding.height; // Max of both sizes + account for matrix edges.
fill.height = resize.height = std::max(sprite_dim.height, text_dim.height) + padding.height; // Max of both sizes + account for matrix edges.
this->icon_width = sprite_dim.width; // Width of bridge icon.
size.width = this->icon_width + WidgetDimensions::scaled.hsep_normal + text_dim.width + padding.width;
@ -239,7 +239,7 @@ public:
for (auto it = first; it != last; ++it) {
const BridgeSpec *b = it->spec;
DrawSpriteIgnorePadding(b->sprite, b->pal, tr.WithWidth(this->icon_width, rtl), SA_HOR_CENTER | SA_BOTTOM);
DrawStringMultiLine(tr.Indent(this->icon_width + WidgetDimensions::scaled.hsep_normal, rtl), GetBridgeSelectString(*it));
DrawStringMultiLineWithClipping(tr.Indent(this->icon_width + WidgetDimensions::scaled.hsep_normal, rtl), GetBridgeSelectString(*it));
tr = tr.Translate(0, this->resize.step_height);
}
break;
@ -283,7 +283,7 @@ public:
}
}
void OnDropdownSelect(WidgetID widget, int index) override
void OnDropdownSelect(WidgetID widget, int index, int) override
{
if (widget == WID_BBS_DROPDOWN_CRITERIA && this->bridges.SortType() != index) {
this->bridges.SetSortType(index);

View File

@ -18,6 +18,8 @@
#include "company_func.h"
#include "vehicle_gui.h"
#include "newgrf_badge.h"
#include "newgrf_badge_config.h"
#include "newgrf_badge_gui.h"
#include "newgrf_engine.h"
#include "newgrf_text.h"
#include "group.h"
@ -72,10 +74,13 @@ static constexpr NWidgetPart _nested_build_vehicle_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDDEN_ENGINES),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetToolTip(STR_TOOLTIP_FILTER_CRITERIA),
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_BV_CONFIGURE_BADGES), SetAspect(WidgetDimensions::ASPECT_UP_DOWN_BUTTON), SetResize(0, 0), SetFill(0, 1), SetSpriteTip(SPR_EXTRA_MENU, STR_BADGE_CONFIG_MENU_TOOLTIP),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY),
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_BV_FILTER), SetResize(1, 0), SetFill(1, 0), SetPadding(2), SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
EndContainer(),
NWidget(NWID_VERTICAL, NWidContainerFlag{}, WID_BV_BADGE_FILTER),
EndContainer(),
EndContainer(),
/* Vehicle list. */
NWidget(NWID_HORIZONTAL),
@ -795,16 +800,20 @@ static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_
*/
static std::optional<std::string> GetNewGRFAdditionalText(EngineID engine)
{
uint16_t callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr);
std::array<int32_t, 16> regs100;
uint16_t callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr, regs100);
if (callback == CALLBACK_FAILED || callback == 0x400) return std::nullopt;
const GRFFile *grffile = Engine::Get(engine)->GetGRF();
assert(grffile != nullptr);
if (callback == 0x40F) {
return GetGRFStringWithTextStack(grffile, static_cast<GRFStringID>(regs100[0]), std::span{regs100}.subspan(1));
}
if (callback > 0x400) {
ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback);
return std::nullopt;
}
return GetGRFStringWithTextStack(grffile, GRFSTR_MISC_GRF_TEXT + callback, 6);
return GetGRFStringWithTextStack(grffile, GRFSTR_MISC_GRF_TEXT + callback, regs100);
}
/**
@ -1122,11 +1131,6 @@ void GUIEngineListAddChildren(GUIEngineList &dst, const GUIEngineList &src, Engi
}
}
/** Enum referring to the Hotkeys in the build vehicle window */
enum BuildVehicleHotkeys : int32_t {
BVHK_FOCUS_FILTER_BOX, ///< Focus the edit box for editing the filter string
};
/** GUI for building vehicles. */
struct BuildVehicleWindow : Window {
VehicleType vehicle_type = VEH_INVALID; ///< Type of vehicles shown in the window.
@ -1147,9 +1151,14 @@ struct BuildVehicleWindow : Window {
TestedEngineDetails te{}; ///< Tested cost and capacity after refit.
GUIBadgeClasses badge_classes{};
static constexpr int BADGE_COLUMNS = 3; ///< Number of columns available for badges (0 = left of image, 1 = between image and name, 2 = after name)
StringFilter string_filter{}; ///< Filter for vehicle name
QueryString vehicle_editbox; ///< Filter editbox
std::pair<WidgetID, WidgetID> badge_filters{}; ///< First and last widgets IDs of badge filters.
BadgeFilterChoices badge_filter_choices{};
void SetBuyVehicleText()
{
NWidgetCore *widget = this->GetWidget<NWidgetCore>(WID_BV_BUILD);
@ -1305,6 +1314,12 @@ struct BuildVehicleWindow : Window {
{
this->badge_classes = GUIBadgeClasses(static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
this->SetCargoFilterArray();
auto container = this->GetWidget<NWidgetContainer>(WID_BV_BADGE_FILTER);
this->badge_filters = AddBadgeDropdownFilters(*container, WID_BV_BADGE_FILTER, COLOUR_GREY, static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
this->widget_lookup.clear();
this->nested_root->FillWidgetLookup(this->widget_lookup);
}
/** Filter the engine list against the currently selected cargo filter */
@ -1345,13 +1360,14 @@ struct BuildVehicleWindow : Window {
/* Figure out what train EngineIDs to put in the list */
void GenerateBuildTrainList(GUIEngineList &list)
{
std::vector<EngineID> variants;
FlatSet<EngineID> variants;
EngineID sel_id = EngineID::Invalid();
size_t num_engines = 0;
list.clear();
BadgeTextFilter btf(this->string_filter, GSF_TRAINS);
BadgeDropdownFilter bdf(this->badge_filter_choices);
/* Make list of all available train engines and wagons.
* Also check to see if the previously selected engine is still available,
@ -1368,6 +1384,8 @@ struct BuildVehicleWindow : Window {
/* Filter now! So num_engines and num_wagons is valid */
if (!FilterSingleEngine(eid)) continue;
if (!bdf.Filter(e->badges)) continue;
/* Filter by name or NewGRF extra text */
if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
@ -1377,8 +1395,7 @@ struct BuildVehicleWindow : Window {
/* Add all parent variants of this engine to the variant list */
EngineID parent = e->info.variant_id;
while (parent != EngineID::Invalid()) {
variants.push_back(parent);
while (parent != EngineID::Invalid() && variants.insert(parent).second) {
parent = Engine::Get(parent)->info.variant_id;
}
@ -1525,11 +1542,10 @@ struct BuildVehicleWindow : Window {
this->FilterEngineList();
/* ensure primary engine of variant group is in list after filtering */
std::vector<EngineID> variants;
FlatSet<EngineID> variants;
for (const auto &item : this->eng_list) {
EngineID parent = item.variant_id;
while (parent != EngineID::Invalid()) {
variants.push_back(parent);
while (parent != EngineID::Invalid() && variants.insert(parent).second) {
parent = Engine::Get(parent)->info.variant_id;
}
}
@ -1573,6 +1589,12 @@ struct BuildVehicleWindow : Window {
return list;
}
DropDownList BuildBadgeConfigurationList() const
{
static const auto separators = {STR_BADGE_CONFIG_PREVIEW, STR_BADGE_CONFIG_NAME};
return BuildBadgeClassConfigurationList(this->badge_classes, BADGE_COLUMNS, separators);
}
void BuildVehicle()
{
EngineID sel_eng = this->sel_engine;
@ -1656,6 +1678,11 @@ struct BuildVehicleWindow : Window {
ShowDropDownList(this, this->BuildCargoDropDownList(), this->cargo_filter_criteria, widget);
break;
case WID_BV_CONFIGURE_BADGES:
if (this->badge_classes.GetClasses().empty()) break;
ShowDropDownList(this, this->BuildBadgeConfigurationList(), -1, widget, 0, false, true);
break;
case WID_BV_SHOW_HIDE: {
const Engine *e = (this->sel_engine == EngineID::Invalid()) ? nullptr : Engine::Get(this->sel_engine);
if (e != nullptr) {
@ -1676,6 +1703,12 @@ struct BuildVehicleWindow : Window {
}
break;
}
default:
if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
ShowDropDownList(this, this->GetWidget<NWidgetBadgeFilter>(widget)->GetDropDownList(), -1, widget, 0, false);
}
break;
}
}
@ -1726,6 +1759,10 @@ struct BuildVehicleWindow : Window {
}
default:
if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
return this->GetWidget<NWidgetBadgeFilter>(widget)->GetStringParameter(this->badge_filter_choices);
}
return this->Window::GetWidgetString(widget, stringid);
}
}
@ -1734,7 +1771,7 @@ struct BuildVehicleWindow : Window {
{
switch (widget) {
case WID_BV_LIST:
resize.height = GetEngineListHeight(this->vehicle_type);
fill.height = resize.height = GetEngineListHeight(this->vehicle_type);
size.height = 3 * resize.height;
size.width = std::max(size.width, this->badge_classes.GetTotalColumnsWidth() + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165) + padding.width;
break;
@ -1755,6 +1792,11 @@ struct BuildVehicleWindow : Window {
size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList()).width + padding.width);
break;
case WID_BV_CONFIGURE_BADGES:
/* Hide the configuration button if no configurable badges are present. */
if (this->badge_classes.GetClasses().empty()) size = {0, 0};
break;
case WID_BV_BUILD:
size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type);
size = maxdim(size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type));
@ -1829,7 +1871,7 @@ struct BuildVehicleWindow : Window {
Command<CMD_RENAME_ENGINE>::Post(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type, this->rename_engine, *str);
}
void OnDropdownSelect(WidgetID widget, int index) override
void OnDropdownSelect(WidgetID widget, int index, int click_result) override
{
switch (widget) {
case WID_BV_SORT_DROPDOWN:
@ -1850,6 +1892,35 @@ struct BuildVehicleWindow : Window {
this->SelectEngine(this->sel_engine);
}
break;
case WID_BV_CONFIGURE_BADGES: {
bool reopen = HandleBadgeConfigurationDropDownClick(static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type), BADGE_COLUMNS, index, click_result, this->badge_filter_choices);
this->ReInit();
if (reopen) {
ReplaceDropDownList(this, this->BuildBadgeConfigurationList(), -1);
} else {
this->CloseChildWindows(WC_DROPDOWN_MENU);
}
/* We need to refresh if a filter is removed. */
this->eng_list.ForceRebuild();
this->SetDirty();
break;
}
default:
if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
if (index < 0) {
ResetBadgeFilter(this->badge_filter_choices, this->GetWidget<NWidgetBadgeFilter>(widget)->GetBadgeClassID());
} else {
SetBadgeFilter(this->badge_filter_choices, BadgeID(index));
}
this->eng_list.ForceRebuild();
this->SetDirty();
}
break;
}
this->SetDirty();
}
@ -1867,23 +1938,8 @@ struct BuildVehicleWindow : Window {
}
}
EventState OnHotkey(int hotkey) override
{
switch (hotkey) {
case BVHK_FOCUS_FILTER_BOX:
this->SetFocusedWidget(WID_BV_FILTER);
SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused.
return ES_HANDLED;
default:
return ES_NOT_HANDLED;
}
return ES_HANDLED;
}
static inline HotkeyList hotkeys{"buildvehicle", {
Hotkey('F', "focus_filter_box", BVHK_FOCUS_FILTER_BOX),
Hotkey('F', "focus_filter_box", WID_BV_FILTER),
}};
};

View File

@ -74,9 +74,8 @@ void CheckCaches()
for (const RoadStop *rs : RoadStop::Iterate()) {
if (IsBayRoadStopTile(rs->xy)) continue;
assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW));
rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs);
rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs);
rs->GetEntry(DIAGDIR_NE).CheckIntegrity(rs);
rs->GetEntry(DIAGDIR_NW).CheckIntegrity(rs);
}
std::vector<NewGRFCache> grf_cache;

View File

@ -410,7 +410,7 @@ void VehicleCargoList::AgeCargo()
return (accepted && cp->first_station != current_station) ? MTA_DELIVER : MTA_KEEP;
} else if (cargo_next == current_station) {
return MTA_DELIVER;
} else if (next_station.Contains(cargo_next.base())) {
} else if (next_station.Contains(cargo_next)) {
return MTA_KEEP;
} else {
return MTA_TRANSFER;
@ -470,7 +470,7 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
new_shares.ChangeShare(current_station, INT_MIN);
StationIDStack excluded = next_station;
while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) {
new_shares.ChangeShare(StationID{excluded.Pop()}, INT_MIN);
new_shares.ChangeShare(excluded.Pop(), INT_MIN);
}
if (new_shares.GetShares()->empty()) {
cargo_next = StationID::Invalid();
@ -743,7 +743,7 @@ uint StationCargoList::ShiftCargo(Taction action, StationIDStack next, bool incl
{
uint max_move = action.MaxMove();
while (!next.IsEmpty()) {
this->ShiftCargo(action, StationID{next.Pop()});
this->ShiftCargo(action, next.Pop());
if (action.MaxMove() == 0) break;
}
if (include_invalid && action.MaxMove() > 0) {
@ -853,7 +853,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac
*/
uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
{
return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid.base(), false);
return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid, false);
}
/*

View File

@ -555,7 +555,7 @@ public:
inline bool HasCargoFor(StationIDStack next) const
{
while (!next.IsEmpty()) {
if (this->packets.find(StationID{next.Pop()}) != this->packets.end()) return true;
if (this->packets.find(next.Pop()) != this->packets.end()) return true;
}
/* Packets for StationID::Invalid() can go anywhere. */
return this->packets.find(StationID::Invalid()) != this->packets.end();

View File

@ -18,5 +18,5 @@ Cheats _cheats;
/** Reinitialise all the cheats. */
void InitializeCheats()
{
memset(&_cheats, 0, sizeof(Cheats));
_cheats = {};
}

View File

@ -35,6 +35,7 @@
#include "timer/timer.h"
#include "timer/timer_game_calendar.h"
#include "timer/timer_game_economy.h"
#include "core/string_consumer.hpp"
#include "widgets/cheat_widget.h"
@ -286,7 +287,7 @@ struct CheatWindow : Window {
case SLE_BOOL: {
bool on = (*(bool*)ce->variable);
DrawBoolButton(button_left, y + button_y_offset, on, true);
DrawBoolButton(button_left, y + button_y_offset, COLOUR_YELLOW, COLOUR_GREY, on, true);
str = GetString(ce->str, on ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
break;
}
@ -354,7 +355,7 @@ struct CheatWindow : Window {
int32_t value = sd->Read(&GetGameSettings());
if (sd->IsBoolSetting()) {
/* Draw checkbox for boolean-value either on/off */
DrawBoolButton(buttons.left, buttons.top, value != 0, editable);
DrawBoolButton(buttons.left, buttons.top, COLOUR_YELLOW, COLOUR_GREY, value != 0, editable);
} else if (sd->flags.Test(SettingFlag::GuiDropdown)) {
/* Draw [v] button for settings of an enum-type */
DrawDropDownButton(buttons.left, buttons.top, COLOUR_YELLOW, state != 0, editable);
@ -607,12 +608,13 @@ struct CheatWindow : Window {
int32_t value;
if (!str->empty()) {
long long llvalue = atoll(str->c_str());
auto llvalue = ParseInteger<int64_t>(*str, 10, true);
if (!llvalue.has_value()) return;
/* Save the correct currency-translated value */
if (sd->flags.Test(SettingFlag::GuiCurrency)) llvalue /= GetCurrency().rate;
if (sd->flags.Test(SettingFlag::GuiCurrency)) llvalue = *llvalue / GetCurrency().rate;
value = ClampTo<int32_t>(llvalue);
value = ClampTo<int32_t>(*llvalue);
} else {
value = sd->GetDefaultValue();
}
@ -621,18 +623,19 @@ struct CheatWindow : Window {
} else {
const CheatEntry *ce = &_cheats_ui[clicked_cheat];
int oldvalue = static_cast<int32_t>(ReadValue(ce->variable, ce->type));
int value = atoi(str->c_str());
auto value = ParseInteger<int32_t>(*str, 10, true);
if (!value.has_value()) return;
*ce->been_used = true;
value = ce->proc(value, value - oldvalue);
value = ce->proc(*value, *value - oldvalue);
if (value != oldvalue) WriteValue(ce->variable, ce->type, static_cast<int64_t>(value));
if (*value != oldvalue) WriteValue(ce->variable, ce->type, static_cast<int64_t>(*value));
}
this->valuewindow_entry = nullptr;
this->SetDirty();
}
IntervalTimer<TimerGameCalendar> daily_interval = {{TimerGameCalendar::MONTH, TimerGameCalendar::Priority::NONE}, [this](auto) {
const IntervalTimer<TimerGameCalendar> daily_interval = {{TimerGameCalendar::MONTH, TimerGameCalendar::Priority::NONE}, [this](auto) {
this->SetDirty();
}};
};

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