mirror of
https://github.com/huderlem/porymap.git
synced 2026-07-02 00:02:04 -05:00
Merge branch 'dev' of https://github.com/huderlem/porymap into local-id
This commit is contained in:
commit
eed58e3aff
|
|
@ -23,6 +23,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
- Add support for defining project values with `enum` where `#define` was expected.
|
||||
- Add a setting to specify the tile values to use for the unused metatile layer.
|
||||
- Add a setting to specify the maximum number of events in a group. A warning will be shown if too many events are added.
|
||||
- Add a setting to customize the size and position of the player view distance.
|
||||
- Add `onLayoutOpened` to the scripting API.
|
||||
|
||||
### Changed
|
||||
|
|
@ -35,7 +36,6 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
- Changes to the "Mirror to Connecting Maps" setting will now be saved between sessions.
|
||||
- A notice will be displayed when attempting to open the "Dynamic" map, rather than nothing happening.
|
||||
- The base game version is now auto-detected if the project name contains only one of "emerald", "firered/leafgreen", or "ruby/sapphire".
|
||||
- The max encounter rate is now read from the project, rather than assuming the default value from RSE.
|
||||
- It's now possible to cancel quitting if there are unsaved changes in sub-windows.
|
||||
- The triple-layer metatiles setting can now be set automatically using a project constant.
|
||||
- `Export Map Stitch Image` and `Export Map Timelapse Image` now show a preview of the full image/gif, not just the current map.
|
||||
|
|
@ -50,6 +50,10 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
- `Script` dropdowns now autocomplete only with scripts from the current map, rather than every script in the project. The old behavior is available via a new setting.
|
||||
- The options for `Encounter Type` and `Terrain Type` in the Tileset Editor are not hardcoded anymore, they're now read from the project.
|
||||
- The `symbol_wild_encounters` setting was replaced; this value is now read from the project.
|
||||
- The max encounter rate is now read from the project, rather than assuming the default value from RSE.
|
||||
- `MAP_OFFSET_W` and `MAP_OFFSET_H` (used to limit the maximum map size) are now read from the project.
|
||||
- The rendered area of the map border is now limited to the maximum player view distance (prior to this it included two extra rows on the top and bottom).
|
||||
- An error message will now be shown when Porymap is unable to save changes (e.g. if Porymap doesn't have write permissions for your project).
|
||||
- A project may now be opened even if it has no maps or map groups. A minimum of one map layout is required.
|
||||
- The file extensions that are expected for `.png` and `.pal` data files and the extensions outputted when creating a new tileset can now be customized.
|
||||
- Miscellaneous performance improvements, especially for opening projects.
|
||||
|
|
@ -58,6 +62,8 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
- Fix `Add Region Map...` not updating the region map settings file.
|
||||
- Fix some crashes on invalid region map tilesets.
|
||||
- Improve error reporting for invalid region map editor settings.
|
||||
- Fix the region map editor's palette resetting between region maps.
|
||||
- Fix the region map editor's h-flip and v-flip settings being swapped.
|
||||
- Fix config files being written before the project is opened successfully.
|
||||
- Fix the map and other project info still displaying if a new project fails to open.
|
||||
- Fix unsaved changes being ignored when quitting (such as with Cmd+Q on macOS).
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ In addition to these files, there are some specific symbol and macro names that
|
|||
``define_pals_total``, ``NUM_PALS_TOTAL``,
|
||||
``define_tiles_per_metatile``, ``NUM_TILES_PER_METATILE``, to determine if triple-layer metatiles are in use. Values other than 8 or 12 are ignored
|
||||
``define_map_size``, ``MAX_MAP_DATA_SIZE``, to limit map dimensions
|
||||
``define_map_offset_width``, ``MAP_OFFSET_W``, to limit map dimensions
|
||||
``define_map_offset_height``, ``MAP_OFFSET_H``, to limit map dimensions
|
||||
``define_mask_metatile``, ``MAPGRID_METATILE_ID_MASK``, optionally read to get settings on ``Maps`` tab
|
||||
``define_mask_collision``, ``MAPGRID_COLLISION_MASK``, optionally read to get settings on ``Maps`` tab
|
||||
``define_mask_elevation``, ``MAPGRID_ELEVATION_MASK``, optionally read to get settings on ``Maps`` tab
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>178</width>
|
||||
<width>188</width>
|
||||
<height>157</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
<string notr="true">.ConnectionsListItem { border-width: 1px; }</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
<item row="3" column="2">
|
||||
<widget class="QToolButton" name="button_Delete">
|
||||
<property name="toolTip">
|
||||
<string>Remove this connection.</string>
|
||||
<string><html><head/><body><p>Remove this connection.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -79,28 +79,28 @@
|
|||
<item row="1" column="1" colspan="2">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Direction">
|
||||
<property name="toolTip">
|
||||
<string>Where the connected map should be positioned relative to the current map.</string>
|
||||
<string><html><head/><body><p>Where the connected map should be positioned relative to the current map.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Map">
|
||||
<property name="toolTip">
|
||||
<string>The name of the map to connect to the current map.</string>
|
||||
<string><html><head/><body><p>The name of the map to connect to the current map.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Offset">
|
||||
<property name="toolTip">
|
||||
<string>The number of spaces to move the connected map perpendicular to its connected direction.</string>
|
||||
<string><html><head/><body><p>The number of spaces to move the connected map perpendicular to its connected direction.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QToolButton" name="button_OpenMap">
|
||||
<property name="toolTip">
|
||||
<string>Open the connected map.</string>
|
||||
<string><html><head/><body><p>Open the connected map.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_Name">
|
||||
<property name="toolTip">
|
||||
<string>The key name for the new JSON field</string>
|
||||
<string><html><head/><body><p>The key name for the new JSON field</p></body></html></string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<item row="2" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Type">
|
||||
<property name="toolTip">
|
||||
<string>The data type for the new JSON field</string>
|
||||
<string><html><head/><body><p>The data type for the new JSON field</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -70,7 +70,7 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The value for the new JSON field</string>
|
||||
<string><html><head/><body><p>The value for the new JSON field</p></body></html></string>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_String">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@
|
|||
<item>
|
||||
<widget class="QPushButton" name="button_CreateNewScript">
|
||||
<property name="toolTip">
|
||||
<string>Create a new Porymap script file with a default template</string>
|
||||
<string><html><head/><body><p>Create a new Porymap script file with a default template</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create New Script...</string>
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
<item>
|
||||
<widget class="QPushButton" name="button_LoadScript">
|
||||
<property name="toolTip">
|
||||
<string>Add an existing script file to the list below</string>
|
||||
<string><html><head/><body><p>Add an existing script file to the list below</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load Script...</string>
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
<item>
|
||||
<widget class="QPushButton" name="button_RefreshScripts">
|
||||
<property name="toolTip">
|
||||
<string>Refresh all loaded scripts to account for any recent edits</string>
|
||||
<string><html><head/><body><p>Refresh all loaded scripts to account for any recent edits</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Refresh Scripts</string>
|
||||
|
|
|
|||
|
|
@ -260,9 +260,6 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_Map">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_9">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
|
|
@ -351,12 +348,6 @@
|
|||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="transformationAnchor">
|
||||
<enum>QGraphicsView::ViewportAnchor::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
<property name="resizeAnchor">
|
||||
<enum>QGraphicsView::ViewportAnchor::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
@ -2386,7 +2377,7 @@
|
|||
<item row="0" column="7">
|
||||
<widget class="QCheckBox" name="checkBox_MirrorConnections">
|
||||
<property name="toolTip">
|
||||
<string>If enabled, connections will automatically be updated on the connected map.</string>
|
||||
<string><html><head/><body><p>If enabled, the connected Emerge and/or Dive maps will be displayed with an opacity set using the slider.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Mirror to Connecting Maps</string>
|
||||
|
|
@ -2435,8 +2426,11 @@
|
|||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QToolButton" name="button_OpenDiveMap">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Open the selected Dive Map</string>
|
||||
<string><html><head/><body><p>Open the selected Dive Map</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -2450,7 +2444,7 @@
|
|||
<item row="0" column="4" rowspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_DiveMapOpacity">
|
||||
<property name="toolTip">
|
||||
<string>If enabled, the connected Emerge and/or Dive maps will be displayed with an opacity set using the slider.</string>
|
||||
<string><html><head/><body><p>If enabled, the connected Emerge and/or Dive maps will be displayed with an opacity set using the slider.</p></body></html></string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Show Emerge/Dive Maps</string>
|
||||
|
|
@ -2569,8 +2563,11 @@
|
|||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QToolButton" name="button_OpenEmergeMap">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Open the selected Emerge Map</string>
|
||||
<string><html><head/><body><p>Open the selected Emerge Map</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -2589,7 +2586,7 @@
|
|||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QGraphicsView" name="graphicsView_Connections">
|
||||
<widget class="ConnectionsView" name="graphicsView_Connections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
|
|
@ -2863,6 +2860,7 @@
|
|||
<addaction name="menuOpen_Recent_Project"/>
|
||||
<addaction name="action_Reload_Project"/>
|
||||
<addaction name="action_Close_Project"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Save"/>
|
||||
<addaction name="action_Save_Project"/>
|
||||
<addaction name="separator"/>
|
||||
|
|
@ -2887,8 +2885,10 @@
|
|||
<addaction name="actionCursor_Tile_Outline"/>
|
||||
<addaction name="actionPlayer_View_Rectangle"/>
|
||||
<addaction name="actionBetter_Cursors"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionDive_Emerge_Map"/>
|
||||
<addaction name="actionShow_Events_In_Map_View"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionShow_Grid"/>
|
||||
<addaction name="actionGrid_Settings"/>
|
||||
</widget>
|
||||
|
|
@ -3076,45 +3076,6 @@
|
|||
<string>Ctrl+T</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSort_by_Location">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/sort_alphabet.ico</normaloff>:/icons/sort_alphabet.ico</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sort by &Location</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSort_by_Group">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/sort_number.ico</normaloff>:/icons/sort_number.ico</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sort by &Group</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Sort by Group</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSort_by_Layout">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/sort_map.ico</normaloff>:/icons/sort_map.ico</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sort by &Layout</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout_Porymap">
|
||||
<property name="text">
|
||||
<string>About Porymap...</string>
|
||||
|
|
@ -3310,9 +3271,14 @@
|
|||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MapView</class>
|
||||
<extends>QWidget</extends>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>mapview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConnectionsView</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>graphicsview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MapTree</class>
|
||||
<extends>QTreeView</extends>
|
||||
|
|
@ -3321,7 +3287,7 @@
|
|||
<customwidget>
|
||||
<class>NoScrollGraphicsView</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>mapview.h</header>
|
||||
<header>graphicsview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>MapListToolBar</class>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>407</width>
|
||||
<height>349</height>
|
||||
<height>380</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -224,7 +224,11 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_LocationName"/>
|
||||
<widget class="QLineEdit" name="lineEdit_LocationName">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The name that will be displayed in-game for this Location. This name will be shared with any other map that has the same Location.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="button_AddFolder">
|
||||
<property name="toolTip">
|
||||
<string>Add a new folder to the list.</string>
|
||||
<string><html><head/><body><p>Add a new folder to the list.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
|
|
@ -73,7 +73,7 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="button_ExpandAll">
|
||||
<property name="toolTip">
|
||||
<string>Expand all folders in the list.</string>
|
||||
<string><html><head/><body><p>Expand all folders in the list.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
|
|
@ -93,7 +93,7 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="button_CollapseAll">
|
||||
<property name="toolTip">
|
||||
<string>Collapse all folders in the list.</string>
|
||||
<string><html><head/><body><p>Collapse all folders in the list.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
|
|
@ -113,7 +113,7 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="button_ToggleEdit">
|
||||
<property name="toolTip">
|
||||
<string>If enabled, folders may be renamed and items in the list may be rearranged.</string>
|
||||
<string><html><head/><body><p>If enabled, folders may be renamed and items in the list may be rearranged.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@
|
|||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<property name="leftMargin">
|
||||
|
|
@ -45,7 +45,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Map">
|
||||
<property name="toolTip">
|
||||
<string>The name of the map to connect to the current map.</string>
|
||||
<string><html><head/><body><p>The name of the map to connect to the current map.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
<item row="1" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_Direction">
|
||||
<property name="toolTip">
|
||||
<string>Where the connected map should be positioned relative to the current map.</string>
|
||||
<string><html><head/><body><p>Where the connected map should be positioned relative to the current map.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -82,10 +82,10 @@
|
|||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_MonitorProjectFiles">
|
||||
<property name="toolTip">
|
||||
<string>If checked, a prompt to reload your project will appear if relevant project files are edited</string>
|
||||
<string><html><head/><body><p>If checked, a prompt to reload your project will appear if relevant project files are edited</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Monitor project files</string>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_OpenRecentProject">
|
||||
<property name="toolTip">
|
||||
<string>If checked, Porymap will automatically open your most recently opened project on startup</string>
|
||||
<string><html><head/><body><p>If checked, Porymap will automatically open your most recently opened project on startup</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open recent project on launch</string>
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_CheckForUpdates">
|
||||
<property name="toolTip">
|
||||
<string>If checked, Porymap will automatically alert you on startup if a new release is available</string>
|
||||
<string><html><head/><body><p>If checked, Porymap will automatically alert you on startup if a new release is available</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Automatically check for updates</string>
|
||||
|
|
@ -112,7 +112,7 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_DisableEventWarning">
|
||||
<property name="toolTip">
|
||||
<string>If checked, no warning will be shown when deleting an event that has an associated #define that may also be deleted.</string>
|
||||
<string><html><head/><body><p>If checked, no warning will be shown when deleting an event that has an associated #define that may also be deleted.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disable warning when deleting events with IDs</string>
|
||||
|
|
@ -138,7 +138,7 @@
|
|||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_OnSprite">
|
||||
<property name="toolTip">
|
||||
<string>If enabled, an event can be selected by clicking directly on the opaque pixels of its sprite. This may be preferable when events are overlapping.</string>
|
||||
<string><html><head/><body><p>If enabled, an event can be selected by clicking directly on the opaque pixels of its sprite. This may be preferable when events are overlapping.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select by clicking on sprite</string>
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_WithinRect">
|
||||
<property name="toolTip">
|
||||
<string>If enabled, an event can be selected by clicking anywhere within its sprite dimensions. This may be preferable for events with small or mostly transparent sprites.</string>
|
||||
<string><html><head/><body><p>If enabled, an event can be selected by clicking anywhere within its sprite dimensions. This may be preferable for events with small or mostly transparent sprites.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select by clicking within bounding rectangle</string>
|
||||
|
|
@ -231,7 +231,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_TextEditorOpenFolder">
|
||||
<property name="toolTip">
|
||||
<string>The shell command for your preferred text editor (possibly an absolute path if the program doesn't exist in your PATH).</string>
|
||||
<string><html><head/><body><p>The shell command for your preferred text editor (possibly an absolute path if the program doesn't exist in your PATH).</p></body></html></string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>e.g. code %D</string>
|
||||
|
|
@ -264,7 +264,7 @@
|
|||
<item row="5" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_TextEditorGotoLine">
|
||||
<property name="toolTip">
|
||||
<string>The shell command for your preferred text editor to open a file to a specific line number (possibly an absolute path if the program doesn't exist in your PATH).</string>
|
||||
<string><html><head/><body><p>The shell command for your preferred text editor to open a file to a specific line number (possibly an absolute path if the program doesn't exist in your PATH).</p></body></html></string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>e.g. code --goto %F:%L</string>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>631</width>
|
||||
<height>600</height>
|
||||
<width>642</width>
|
||||
<height>609</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -38,8 +38,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>559</width>
|
||||
<height>589</height>
|
||||
<width>570</width>
|
||||
<height>692</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_UsePoryscript">
|
||||
<property name="toolTip">
|
||||
<string>Whether map script files should prefer using .pory</string>
|
||||
<string><html><head/><body><p>Whether map script files should prefer using .pory</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use Poryscript</string>
|
||||
|
|
@ -61,6 +61,9 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_ShowWildEncounterTables">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If enabled, Porymap will display wild encounter data on the Wild Pokémon tab.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Wild Encounter Tables</string>
|
||||
</property>
|
||||
|
|
@ -99,7 +102,7 @@
|
|||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="button_ImportDefaultPrefabs">
|
||||
<property name="toolTip">
|
||||
<string>Restore the data in the prefabs file to the version defaults. Will create a new file if one doesn't exist.</string>
|
||||
<string><html><head/><body><p>Restore the data in the prefabs file to the version defaults. Will create a new file if one doesn't exist.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Import Defaults</string>
|
||||
|
|
@ -109,7 +112,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_PrefabsPath">
|
||||
<property name="toolTip">
|
||||
<string>The file that will be used to populate the Prefabs tab</string>
|
||||
<string><html><head/><body><p>The file that will be used to populate the Prefabs tab</p></body></html></string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>prefabs.json</string>
|
||||
|
|
@ -148,7 +151,7 @@
|
|||
<item row="0" column="1" colspan="6">
|
||||
<widget class="QLineEdit" name="lineEdit_CollisionGraphics">
|
||||
<property name="toolTip">
|
||||
<string>The image sheet that will be used to represent elevation and collision on the Collision tab</string>
|
||||
<string><html><head/><body><p>The image sheet that will be used to represent elevation and collision on the Collision tab</p></body></html></string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
|
|
@ -176,7 +179,7 @@
|
|||
<item row="1" column="5">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_MaxCollision">
|
||||
<property name="toolTip">
|
||||
<string>The maximum collision value represented with an icon on the image sheet</string>
|
||||
<string><html><head/><body><p>The maximum collision value represented with an icon on the image sheet</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -197,7 +200,7 @@
|
|||
<item row="1" column="2">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_MaxElevation">
|
||||
<property name="toolTip">
|
||||
<string>The maximum elevation value represented with an icon on the image sheet</string>
|
||||
<string><html><head/><body><p>The maximum elevation value represented with an icon on the image sheet</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -270,7 +273,7 @@
|
|||
<item row="1" column="2" colspan="3">
|
||||
<widget class="QLineEdit" name="lineEdit_PokemonIcon">
|
||||
<property name="toolTip">
|
||||
<string>The icon that will be displayed on the Wild Pokémon tab for the above species</string>
|
||||
<string><html><head/><body><p>The icon that will be displayed on the Wild Pokémon tab for the above species</p></body></html></string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
|
|
@ -280,6 +283,91 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_PlayerViewDistance">
|
||||
<property name="title">
|
||||
<string>Player View Distance</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_PlayerViewDistanceCol1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_PlayerViewDistance_North">
|
||||
<property name="text">
|
||||
<string>North</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_PlayerViewDistance_South">
|
||||
<property name="text">
|
||||
<string>South</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_PlayerViewDistance_North">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The distance (in pixels) that a player is able to see North of their character's position in-game. By default this is the distance from the center 16x16 to the edge of the 160 pixel tall GBA screen.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_PlayerViewDistance_South">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The distance (in pixels) that a player is able to see South of their character's position in-game. By default this is the distance from the center 16x16 to the edge of the 160 pixel tall GBA screen.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_PlayerViewDistanceCol2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_PlayerViewDistance_West">
|
||||
<property name="text">
|
||||
<string>West</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_PlayerViewDistance_East">
|
||||
<property name="text">
|
||||
<string>East</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_PlayerViewDistance_West">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The distance (in pixels) that a player is able to see West of their character's position in-game. By default this is the distance from the center 16x16 to the edge of the 240 pixel wide GBA screen.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_PlayerViewDistance_East">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The distance (in pixels) that a player is able to see East of their character's position in-game. By default this is the distance from the center 16x16 to the edge of the 240 pixel wide GBA screen.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_Warning">
|
||||
<property name="styleSheet">
|
||||
|
|
@ -378,8 +466,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>559</width>
|
||||
<height>560</height>
|
||||
<width>570</width>
|
||||
<height>622</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
|
|
@ -389,37 +477,6 @@
|
|||
<string>Map Data Defaults</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QWidget" name="widget_CustomSizeBorderMetatiles" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_FillMetatile">
|
||||
<property name="toolTip">
|
||||
<string>The default metatile value that will be used to fill new maps</string>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string>0x</string>
|
||||
</property>
|
||||
<property name="displayIntegerBase">
|
||||
<number>16</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_Elevation">
|
||||
<property name="text">
|
||||
|
|
@ -427,6 +484,50 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_MapWidth">
|
||||
<property name="text">
|
||||
<string>Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Elevation">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default elevation that will be used to fill new maps</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBox_CreateTextFile">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Whether a separate text.inc or text.pory file will be created for new maps, alongside the scripts file</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create separate text file</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_MapWidth">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default layout width for new maps</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_MapHeight">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default layout height for new maps</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_FillMetatile">
|
||||
<property name="text">
|
||||
|
|
@ -434,13 +535,10 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="checkBox_CreateTextFile">
|
||||
<property name="toolTip">
|
||||
<string>Whether a separate text.inc or text.pory file will be created for new maps, alongside the scripts file</string>
|
||||
</property>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_Collision">
|
||||
<property name="text">
|
||||
<string>Create separate text file</string>
|
||||
<string>Collision</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -451,6 +549,20 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_FillMetatile">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default metatile value that will be used to fill new maps</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Collision">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default collision that will be used to fill new maps</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="3">
|
||||
<widget class="QStackedWidget" name="stackedWidget_BorderMetatiles">
|
||||
<widget class="QWidget" name="page_CustomBorderSize">
|
||||
|
|
@ -470,7 +582,7 @@
|
|||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_BorderMetatiles">
|
||||
<property name="toolTip">
|
||||
<string>A comma-separated list of metatile values that will be used to fill new map borders</string>
|
||||
<string><html><head/><body><p>A comma-separated list of metatile values that will be used to fill new map borders</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -491,54 +603,30 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="NoScrollSpinBox" name="spinBox_BorderMetatile1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_BorderMetatile1">
|
||||
<property name="toolTip">
|
||||
<string>The default metatile value that will be used for the top-left border metatile on new maps.</string>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string>0x</string>
|
||||
</property>
|
||||
<property name="displayIntegerBase">
|
||||
<number>16</number>
|
||||
<string><html><head/><body><p>The default metatile value that will be used for the top-left border metatile on new maps.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollSpinBox" name="spinBox_BorderMetatile2">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_BorderMetatile2">
|
||||
<property name="toolTip">
|
||||
<string>The default metatile value that will be used for the top-right border metatile on new maps.</string>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string>0x</string>
|
||||
</property>
|
||||
<property name="displayIntegerBase">
|
||||
<number>16</number>
|
||||
<string><html><head/><body><p>The default metatile value that will be used for the top-right border metatile on new maps.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollSpinBox" name="spinBox_BorderMetatile3">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_BorderMetatile3">
|
||||
<property name="toolTip">
|
||||
<string>The default metatile value that will be used for the bottom-left border metatile on new maps.</string>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string>0x</string>
|
||||
</property>
|
||||
<property name="displayIntegerBase">
|
||||
<number>16</number>
|
||||
<string><html><head/><body><p>The default metatile value that will be used for the bottom-left border metatile on new maps.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollSpinBox" name="spinBox_BorderMetatile4">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_BorderMetatile4">
|
||||
<property name="toolTip">
|
||||
<string>The default metatile value that will be used for the bottom-right border metatile on new maps.</string>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string>0x</string>
|
||||
</property>
|
||||
<property name="displayIntegerBase">
|
||||
<number>16</number>
|
||||
<string><html><head/><body><p>The default metatile value that will be used for the bottom-right border metatile on new maps.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -546,24 +634,28 @@
|
|||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Elevation">
|
||||
<property name="toolTip">
|
||||
<string>The default elevation that will be used to fill new maps</string>
|
||||
</property>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QWidget" name="widget_CustomSizeBorderMetatiles" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_Collision">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_MapHeight">
|
||||
<property name="text">
|
||||
<string>Collision</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="NoScrollSpinBox" name="spinBox_Collision">
|
||||
<property name="toolTip">
|
||||
<string>The default collision that will be used to fill new maps</string>
|
||||
<string>Height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -614,7 +706,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_MetatileIdMask">
|
||||
<property name="toolTip">
|
||||
<string>The mask used to read/write metatile IDs in map data.</string>
|
||||
<string><html><head/><body><p>The mask used to read/write metatile IDs in map data.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -628,7 +720,7 @@
|
|||
<item row="1" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_CollisionMask">
|
||||
<property name="toolTip">
|
||||
<string>The mask used to read/write collision values in map data.</string>
|
||||
<string><html><head/><body><p>The mask used to read/write collision values in map data.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -642,7 +734,7 @@
|
|||
<item row="2" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_ElevationMask">
|
||||
<property name="toolTip">
|
||||
<string>The mask used to read/write elevation values in map data.</string>
|
||||
<string><html><head/><body><p>The mask used to read/write elevation values in map data.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -671,7 +763,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="checkBox_EnableAllowFlags">
|
||||
<property name="toolTip">
|
||||
<string>Whether "Allow Running", "Allow Biking" and "Allow Dig & Escape Rope" are default options for Map Headers</string>
|
||||
<string><html><head/><body><p>Whether &quot;Allow Running&quot;, &quot;Allow Biking&quot; and &quot;Allow Dig &amp; Escape Rope&quot; are default options for Map Headers</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable 'Allow Running/Biking/Escaping'</string>
|
||||
|
|
@ -681,7 +773,7 @@
|
|||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_EnableFloorNumber">
|
||||
<property name="toolTip">
|
||||
<string>Whether "Floor Number" is a default option for Map Headers</string>
|
||||
<string><html><head/><body><p>Whether &quot;Floor Number&quot; is a default option for Map Headers</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable 'Floor Number'</string>
|
||||
|
|
@ -691,7 +783,7 @@
|
|||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_EnableCustomBorderSize">
|
||||
<property name="toolTip">
|
||||
<string>Whether the dimensions of the border can be changed. If not set, all borders are 2x2</string>
|
||||
<string><html><head/><body><p>Whether the dimensions of the border can be changed. If not set, all borders are 2x2</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Custom Border Size</string>
|
||||
|
|
@ -751,7 +843,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>559</width>
|
||||
<width>570</width>
|
||||
<height>798</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
|
@ -770,7 +862,11 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_DefaultPrimaryTileset"/>
|
||||
<widget class="NoScrollComboBox" name="comboBox_DefaultPrimaryTileset">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default primary tileset to use for new maps/layouts.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_SecondaryTileset">
|
||||
|
|
@ -780,7 +876,11 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_DefaultSecondaryTileset"/>
|
||||
<widget class="NoScrollComboBox" name="comboBox_DefaultSecondaryTileset">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The default secondary tileset to use for new maps/layouts.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
@ -794,7 +894,7 @@
|
|||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_RenderBlack">
|
||||
<property name="toolTip">
|
||||
<string>Fully transparent pixels will be rendered as black pixels (the Pokémon games do this by default)</string>
|
||||
<string><html><head/><body><p>Fully transparent pixels will be rendered as black pixels (the Pokémon games do this by default)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Render as black</string>
|
||||
|
|
@ -804,7 +904,7 @@
|
|||
<item>
|
||||
<widget class="QRadioButton" name="radioButton_RenderFirstPalColor">
|
||||
<property name="toolTip">
|
||||
<string>Fully transparent pixels will be rendered using the first palette color (this the default behavior for the GBA)</string>
|
||||
<string><html><head/><body><p>Fully transparent pixels will be rendered using the first palette color (this the default behavior for the GBA)</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Render using first palette color</string>
|
||||
|
|
@ -830,7 +930,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_UnusedTileNormal">
|
||||
<property name="toolTip">
|
||||
<string>This raw tile value will be used to fill the unused bottom layer of Normal metatiles</string>
|
||||
<string><html><head/><body><p>This raw tile value will be used to fill the unused bottom layer of Normal metatiles</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -844,7 +944,7 @@
|
|||
<item row="1" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_UnusedTileCovered">
|
||||
<property name="toolTip">
|
||||
<string>This raw tile value will be used to fill the unused top layer of Covered metatiles</string>
|
||||
<string><html><head/><body><p>This raw tile value will be used to fill the unused top layer of Covered metatiles</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -858,7 +958,7 @@
|
|||
<item row="2" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_UnusedTileSplit">
|
||||
<property name="toolTip">
|
||||
<string>This raw tile value will be used to fill the unused middle layer of Split metatiles</string>
|
||||
<string><html><head/><body><p>This raw tile value will be used to fill the unused middle layer of Split metatiles</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -902,22 +1002,19 @@
|
|||
<item row="4" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_LayerTypeMask">
|
||||
<property name="toolTip">
|
||||
<string>The mask used to read/write Layer Type from the metatile's attributes data. If 0, this attribute is disabled.</string>
|
||||
<string><html><head/><body><p>The mask used to read/write Layer Type from the metatile's attributes data. If 0, this attribute is disabled.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_BehaviorMask">
|
||||
<property name="toolTip">
|
||||
<string>The mask used to read/write Metatile Behavior from the metatile's attributes data. If 0, this attribute is disabled.</string>
|
||||
<string><html><head/><body><p>The mask used to read/write Metatile Behavior from the metatile's attributes data. If 0, this attribute is disabled.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_AttributesSize">
|
||||
<property name="toolTip">
|
||||
<string>The number of bytes used per metatile for metatile attributes</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Attributes size (in bytes)</string>
|
||||
</property>
|
||||
|
|
@ -948,6 +1045,9 @@
|
|||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBox_EnableTripleLayerMetatiles">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If checked, metatiles will be interpreted as having 3 layers of 4 tiles each (12 tiles total) as opposed to the default 2 layers of 4 tiles each (8 total).</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Triple Layer Metatiles</string>
|
||||
</property>
|
||||
|
|
@ -956,7 +1056,7 @@
|
|||
<item row="7" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_TerrainTypeMask">
|
||||
<property name="toolTip">
|
||||
<string>The mask used to read/write Terrain Type from the metatile's attributes data. If 0, this attribute is disabled.</string>
|
||||
<string><html><head/><body><p>The mask used to read/write Terrain Type from the metatile's attributes data. If 0, this attribute is disabled.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -983,7 +1083,7 @@
|
|||
<item row="5" column="1">
|
||||
<widget class="UIntHexSpinBox" name="spinBox_EncounterTypeMask">
|
||||
<property name="toolTip">
|
||||
<string>The mask used to read/write Encounter Type from the metatile's attributes data. If 0, this attribute is disabled.</string>
|
||||
<string><html><head/><body><p>The mask used to read/write Encounter Type from the metatile's attributes data. If 0, this attribute is disabled.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -996,6 +1096,9 @@
|
|||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="NoScrollComboBox" name="comboBox_AttributesSize">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The number of bytes each metatile has for metatile attributes. This is the metadata about each metatile like behvior, layer type, etc.</p></body></html></string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
|
|
@ -1036,7 +1139,7 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_OutputCallback">
|
||||
<property name="toolTip">
|
||||
<string>Whether the C data outputted for new tilesets will include the "callback" field</string>
|
||||
<string><html><head/><body><p>Whether the C data outputted for new tilesets will include the &quot;callback&quot; field</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Output 'callback' field</string>
|
||||
|
|
@ -1046,7 +1149,7 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_OutputIsCompressed">
|
||||
<property name="toolTip">
|
||||
<string>Whether the C data outputted for new tilesets will include the "isCompressed" field</string>
|
||||
<string><html><head/><body><p>Whether the C data outputted for new tilesets will include the &quot;isCompressed&quot; field</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Output 'isCompressed' field</string>
|
||||
|
|
@ -1093,7 +1196,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>559</width>
|
||||
<width>570</width>
|
||||
<height>840</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
|
@ -1121,7 +1224,7 @@
|
|||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_WarpsIcon">
|
||||
<property name="toolTip">
|
||||
<string>The icon that will be used to represent Warp events</string>
|
||||
<string><html><head/><body><p>The icon that will be used to represent Warp events</p></body></html></string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
|
|
@ -1131,7 +1234,7 @@
|
|||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_HealLocationsIcon">
|
||||
<property name="toolTip">
|
||||
<string>The icon that will be used to represent Heal Location events</string>
|
||||
<string><html><head/><body><p>The icon that will be used to represent Heal Location events</p></body></html></string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
|
|
@ -1155,7 +1258,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_ObjectsIcon">
|
||||
<property name="toolTip">
|
||||
<string>The icon that will be used to represent Object events that don't have their own sprite</string>
|
||||
<string><html><head/><body><p>The icon that will be used to represent Object events that don't have their own sprite</p></body></html></string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
|
|
@ -1172,7 +1275,7 @@
|
|||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_TriggersIcon">
|
||||
<property name="toolTip">
|
||||
<string>The icon that will be used to represent Trigger events</string>
|
||||
<string><html><head/><body><p>The icon that will be used to represent Trigger events</p></body></html></string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
|
|
@ -1182,7 +1285,7 @@
|
|||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_BGsIcon">
|
||||
<property name="toolTip">
|
||||
<string>The icon that will be used to represent BG events</string>
|
||||
<string><html><head/><body><p>The icon that will be used to represent BG events</p></body></html></string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
|
|
@ -1256,7 +1359,7 @@
|
|||
<item row="1" column="2">
|
||||
<widget class="QToolButton" name="button_RemoveWarpBehavior">
|
||||
<property name="toolTip">
|
||||
<string>Remove the current text from the list</string>
|
||||
<string><html><head/><body><p>Remove the current text from the list</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -1280,7 +1383,7 @@
|
|||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QCheckBox" name="checkBox_DisableWarning">
|
||||
<property name="toolTip">
|
||||
<string>If checked, Warp Events will not display a warning about incompatible metatile behaviors</string>
|
||||
<string><html><head/><body><p>If checked, Warp Events will not display a warning about incompatible metatile behaviors</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disable Warning</string>
|
||||
|
|
@ -1291,9 +1394,9 @@
|
|||
<widget class="NoScrollComboBox" name="comboBox_WarpBehaviors"/>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="3">
|
||||
<widget class="QTextEdit" name="textEdit_WarpBehaviors">
|
||||
<widget class="NoScrollTextEdit" name="textEdit_WarpBehaviors">
|
||||
<property name="toolTip">
|
||||
<string>Metatile Behaviors on this list won't trigger warnings for Warp Events</string>
|
||||
<string><html><head/><body><p>Metatile Behaviors on this list won't trigger warnings for Warp Events</p></body></html></string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
|
|
@ -1309,7 +1412,7 @@
|
|||
<item row="1" column="1">
|
||||
<widget class="QToolButton" name="button_AddWarpBehavior">
|
||||
<property name="toolTip">
|
||||
<string>Add the current text to the list</string>
|
||||
<string><html><head/><body><p>Add the current text to the list</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
|
|
@ -1475,8 +1578,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>559</width>
|
||||
<height>490</height>
|
||||
<width>570</width>
|
||||
<height>499</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
|
|
@ -1522,8 +1625,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>533</width>
|
||||
<height>428</height>
|
||||
<width>544</width>
|
||||
<height>437</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="layout_ProjectPaths">
|
||||
|
|
@ -1564,8 +1667,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>559</width>
|
||||
<height>490</height>
|
||||
<width>570</width>
|
||||
<height>499</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
|
|
@ -1611,8 +1714,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>533</width>
|
||||
<height>428</height>
|
||||
<width>544</width>
|
||||
<height>437</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="layout_Identifiers">
|
||||
|
|
@ -1661,6 +1764,11 @@
|
|||
<extends>QSpinBox</extends>
|
||||
<header>noscrollspinbox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>NoScrollTextEdit</class>
|
||||
<extends>QTextEdit</extends>
|
||||
<header>noscrolltextedit.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>UIntSpinBox</class>
|
||||
<extends>QAbstractSpinBox</extends>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
<enum>QFormLayout::FieldGrowthPolicy::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="config_alias">
|
||||
<property name="toolTip">
|
||||
<string>A nickname for this region map that will differentiate it from others (should be unique).</string>
|
||||
<string><html><head/><body><p>A nickname for this region map that will differentiate it from others (should be unique).</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -131,7 +131,7 @@
|
|||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The height of the tilemap</string>
|
||||
<string><html><head/><body><p>The height of the tilemap</p></body></html></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
|
|
@ -148,10 +148,10 @@
|
|||
<item row="6" column="1">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
|
|
@ -218,10 +218,10 @@
|
|||
<string><html><head/><body><p>Path to the tilemap binary relative to the project root.</p></body></html></string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
|
|
@ -269,10 +269,10 @@
|
|||
<item row="10" column="1">
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
|
|
@ -392,10 +392,10 @@
|
|||
<item row="2" column="1">
|
||||
<widget class="QFrame" name="frame_5">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="leftMargin">
|
||||
|
|
@ -487,7 +487,7 @@
|
|||
<item>
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -517,7 +517,7 @@
|
|||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -590,7 +590,7 @@
|
|||
<item>
|
||||
<spacer name="horizontalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -617,7 +617,7 @@
|
|||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -646,7 +646,7 @@
|
|||
<item row="9" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
|
|
@ -659,10 +659,10 @@
|
|||
<item row="9" column="1">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
|
||||
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>8</number>
|
||||
|
|
|
|||
|
|
@ -14,19 +14,20 @@
|
|||
#include <QGraphicsPixmapItem>
|
||||
|
||||
#include "events.h"
|
||||
#include "gridsettings.h"
|
||||
|
||||
static const QVersionNumber porymapVersion = QVersionNumber::fromString(PORYMAP_VERSION);
|
||||
extern const QVersionNumber porymapVersion;
|
||||
|
||||
// In both versions the default new map border is a generic tree
|
||||
#define DEFAULT_BORDER_RSE (QList<uint16_t>{0x1D4, 0x1D5, 0x1DC, 0x1DD})
|
||||
#define DEFAULT_BORDER_FRLG (QList<uint16_t>{0x14, 0x15, 0x1C, 0x1D})
|
||||
// Distance in pixels from the edge of a GBA screen (240x160) to the center 16x16 pixels.
|
||||
#define GBA_H_DIST_TO_CENTER ((240-16)/2)
|
||||
#define GBA_V_DIST_TO_CENTER ((160-16)/2)
|
||||
|
||||
#define CONFIG_BACKWARDS_COMPATABILITY
|
||||
|
||||
class KeyValueConfigBase
|
||||
{
|
||||
public:
|
||||
void save();
|
||||
bool save();
|
||||
void load();
|
||||
virtual ~KeyValueConfigBase();
|
||||
virtual void reset() = 0;
|
||||
|
|
@ -36,9 +37,11 @@ protected:
|
|||
virtual QMap<QString, QString> getKeyValueMap() = 0;
|
||||
virtual void init() = 0;
|
||||
virtual void setUnreadKeys() = 0;
|
||||
bool getConfigBool(QString key, QString value);
|
||||
int getConfigInteger(QString key, QString value, int min = INT_MIN, int max = INT_MAX, int defaultValue = 0);
|
||||
uint32_t getConfigUint32(QString key, QString value, uint32_t min = 0, uint32_t max = UINT_MAX, uint32_t defaultValue = 0);
|
||||
|
||||
static bool getConfigBool(const QString &key, const QString &value);
|
||||
static int getConfigInteger(const QString &key, const QString &value, int min = INT_MIN, int max = INT_MAX, int defaultValue = 0);
|
||||
static uint32_t getConfigUint32(const QString &key, const QString &value, uint32_t min = 0, uint32_t max = UINT_MAX, uint32_t defaultValue = 0);
|
||||
static QColor getConfigColor(const QString &key, const QString &value, const QColor &defaultValue = Qt::black);
|
||||
};
|
||||
|
||||
class PorymapConfig: public KeyValueConfigBase
|
||||
|
|
@ -92,6 +95,7 @@ public:
|
|||
this->rateLimitTimes.clear();
|
||||
this->eventSelectionShapeMode = QGraphicsPixmapItem::MaskShape;
|
||||
this->shownInGameReloadMessage = false;
|
||||
this->gridSettings = GridSettings();
|
||||
}
|
||||
void addRecentProject(QString project);
|
||||
void setRecentProjects(QStringList projects);
|
||||
|
|
@ -156,6 +160,7 @@ public:
|
|||
QByteArray newMapDialogGeometry;
|
||||
QByteArray newLayoutDialogGeometry;
|
||||
bool shownInGameReloadMessage;
|
||||
GridSettings gridSettings;
|
||||
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
|
|
@ -214,6 +219,8 @@ enum ProjectIdentifier {
|
|||
define_pals_total,
|
||||
define_tiles_per_metatile,
|
||||
define_map_size,
|
||||
define_map_offset_width,
|
||||
define_map_offset_height,
|
||||
define_mask_metatile,
|
||||
define_mask_collision,
|
||||
define_mask_elevation,
|
||||
|
|
@ -317,6 +324,7 @@ public:
|
|||
this->defaultMetatileId = 1;
|
||||
this->defaultElevation = 3;
|
||||
this->defaultCollision = 0;
|
||||
this->defaultMapSize = QSize(20,20);
|
||||
this->defaultPrimaryTileset = "gTileset_General";
|
||||
this->prefabFilepath = QString();
|
||||
this->prefabImportPrompted = false;
|
||||
|
|
@ -328,8 +336,8 @@ public:
|
|||
this->eventIconPaths.clear();
|
||||
this->pokemonIconPaths.clear();
|
||||
this->collisionSheetPath = QString();
|
||||
this->collisionSheetWidth = 2;
|
||||
this->collisionSheetHeight = 16;
|
||||
this->collisionSheetSize = QSize(2, 16);
|
||||
this->playerViewDistance = QMargins(GBA_H_DIST_TO_CENTER, GBA_V_DIST_TO_CENTER, GBA_H_DIST_TO_CENTER, GBA_V_DIST_TO_CENTER);
|
||||
this->blockMetatileIdMask = 0x03FF;
|
||||
this->blockCollisionMask = 0x0C00;
|
||||
this->blockElevationMask = 0xF000;
|
||||
|
|
@ -382,6 +390,7 @@ public:
|
|||
uint16_t defaultMetatileId;
|
||||
uint16_t defaultElevation;
|
||||
uint16_t defaultCollision;
|
||||
QSize defaultMapSize;
|
||||
QList<uint16_t> newMapBorderMetatileIds;
|
||||
QString defaultPrimaryTileset;
|
||||
QString defaultSecondaryTileset;
|
||||
|
|
@ -404,8 +413,8 @@ public:
|
|||
uint16_t unusedTileSplit;
|
||||
bool mapAllowFlagsEnabled;
|
||||
QString collisionSheetPath;
|
||||
int collisionSheetWidth;
|
||||
int collisionSheetHeight;
|
||||
QSize collisionSheetSize;
|
||||
QMargins playerViewDistance;
|
||||
QList<uint32_t> warpBehaviors;
|
||||
int maxEventsPerGroup;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,10 +22,6 @@
|
|||
#define MAX_BORDER_WIDTH 255
|
||||
#define MAX_BORDER_HEIGHT 255
|
||||
|
||||
// Number of metatiles to draw out from edge of map. Could allow modification of this in the future.
|
||||
// porymap will reflect changes to it, but the value is hard-coded in the projects at the moment
|
||||
#define BORDER_DISTANCE 7
|
||||
|
||||
class LayoutPixmapItem;
|
||||
class CollisionPixmapItem;
|
||||
class BorderMetatilesPixmapItem;
|
||||
|
|
@ -89,6 +85,7 @@ public:
|
|||
|
||||
void deleteConnections();
|
||||
QList<MapConnection*> getConnections() const { return m_connections; }
|
||||
MapConnection* getConnection(const QString &direction) const;
|
||||
void removeConnection(MapConnection *);
|
||||
void addConnection(MapConnection *);
|
||||
void loadConnection(MapConnection *);
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ public:
|
|||
int getHeight() const { return height; }
|
||||
int getBorderWidth() const { return border_width; }
|
||||
int getBorderHeight() const { return border_height; }
|
||||
int getBorderDrawWidth() const;
|
||||
int getBorderDrawHeight() const;
|
||||
QMargins getBorderMargins() const;
|
||||
QRect getVisibleRect() const;
|
||||
|
||||
bool isWithinBounds(int x, int y) const;
|
||||
bool isWithinBounds(const QRect &rect) const;
|
||||
|
|
@ -116,9 +116,12 @@ public:
|
|||
void clearBorderCache();
|
||||
void cacheBorder();
|
||||
|
||||
void setClean();
|
||||
bool hasUnsavedChanges() const;
|
||||
|
||||
bool save(const QString &root);
|
||||
bool saveBorder(const QString &root);
|
||||
bool saveBlockdata(const QString &root);
|
||||
|
||||
bool layoutBlockChanged(int i, const Blockdata &cache);
|
||||
|
||||
uint16_t getBorderMetatileId(int x, int y);
|
||||
|
|
@ -143,6 +146,7 @@ public:
|
|||
private:
|
||||
void setNewDimensionsBlockdata(int newWidth, int newHeight);
|
||||
void setNewBorderDimensionsBlockdata(int newWidth, int newHeight);
|
||||
bool writeBlockdata(const QString &path, const Blockdata &blockdata) const;
|
||||
|
||||
static int getBorderDrawDistance(int dimension, qreal minimum);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace PaletteUtil {
|
||||
QList<QRgb> parse(QString filepath, bool *error);
|
||||
void writeJASC(QString filepath, QVector<QRgb> colors, int offset, int nColors);
|
||||
bool writeJASC(const QString &filepath, const QVector<QRgb> &colors, int offset, int nColors);
|
||||
}
|
||||
|
||||
#endif // PALETTEUTIL_H
|
||||
|
|
|
|||
|
|
@ -55,17 +55,17 @@ public:
|
|||
static QString getExpectedDir(QString tilesetName, bool isSecondary);
|
||||
QString getExpectedDir();
|
||||
|
||||
void load();
|
||||
void loadMetatiles();
|
||||
void loadMetatileAttributes();
|
||||
void loadTilesImage(QImage *importedImage = nullptr);
|
||||
void loadPalettes();
|
||||
bool load();
|
||||
bool loadMetatiles();
|
||||
bool loadMetatileAttributes();
|
||||
bool loadTilesImage(QImage *importedImage = nullptr);
|
||||
bool loadPalettes();
|
||||
|
||||
void save();
|
||||
void saveMetatileAttributes();
|
||||
void saveMetatiles();
|
||||
void saveTilesImage();
|
||||
void savePalettes();
|
||||
bool save();
|
||||
bool saveMetatileAttributes();
|
||||
bool saveMetatiles();
|
||||
bool saveTilesImage();
|
||||
bool savePalettes();
|
||||
|
||||
bool appendToHeaders(QString root, QString friendlyName, bool usingAsm);
|
||||
bool appendToGraphics(QString root, QString friendlyName, bool usingAsm);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace Util {
|
|||
int roundUp(int numToRound, int multiple);
|
||||
QString toDefineCase(QString input);
|
||||
QString toHexString(uint32_t value, int minLength = 0);
|
||||
QString toHtmlParagraph(const QString &text);
|
||||
Qt::Orientations getOrientation(bool xflip, bool yflip);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ public:
|
|||
GridSettings gridSettings;
|
||||
|
||||
void setProject(Project * project);
|
||||
void saveAll();
|
||||
void saveCurrent();
|
||||
bool saveAll();
|
||||
bool saveCurrent();
|
||||
void saveEncounterTabData();
|
||||
|
||||
void closeProject();
|
||||
|
|
@ -92,14 +92,16 @@ public:
|
|||
void setConnectionsVisibility(bool visible);
|
||||
void updateDivingMapsVisibility();
|
||||
void renderDivingConnections();
|
||||
void addConnection(MapConnection* connection);
|
||||
void addNewConnection(const QString &mapName, const QString &direction);
|
||||
void replaceConnection(const QString &mapName, const QString &direction);
|
||||
void removeConnection(MapConnection* connection);
|
||||
void removeSelectedConnection();
|
||||
void addNewWildMonGroup(QWidget *window);
|
||||
void deleteWildMonGroup();
|
||||
void configureEncounterJSON(QWidget *);
|
||||
EncounterTableModel* getCurrentWildMonTable();
|
||||
void updateDiveMap(QString mapName);
|
||||
void updateEmergeMap(QString mapName);
|
||||
bool setDivingMapName(const QString &mapName, const QString &direction);
|
||||
QString getDivingMapName(const QString &direction) const;
|
||||
void setSelectedConnection(MapConnection *connection);
|
||||
|
||||
void updatePrimaryTileset(QString tilesetLabel, bool forceLoad = false);
|
||||
|
|
@ -120,6 +122,7 @@ public:
|
|||
void updateEventPixmapItemZValue(EventPixmapItem *item);
|
||||
qreal getEventOpacity(const Event *event) const;
|
||||
|
||||
void setPlayerViewRect(const QRectF &rect);
|
||||
void updateCursorRectPos(int x, int y);
|
||||
void setCursorRectVisible(bool visible);
|
||||
|
||||
|
|
@ -215,7 +218,7 @@ private:
|
|||
|
||||
EditMode editMode = EditMode::None;
|
||||
|
||||
void save(bool currentOnly);
|
||||
bool save(bool currentOnly);
|
||||
void clearMap();
|
||||
void clearMetatileSelector();
|
||||
void clearMovementPermissionSelector();
|
||||
|
|
@ -234,8 +237,9 @@ private:
|
|||
void removeConnectionPixmap(MapConnection *connection);
|
||||
void displayConnection(MapConnection *connection);
|
||||
void displayDivingConnection(MapConnection *connection);
|
||||
void setDivingMapName(QString mapName, QString direction);
|
||||
void removeDivingMapPixmap(MapConnection *connection);
|
||||
void onDivingMapEditingFinished(NoScrollComboBox* combo, const QString &direction);
|
||||
void updateDivingMapButton(QToolButton* button, const QString &mapName);
|
||||
void updateEncounterFields(EncounterFields newFields);
|
||||
QString getMovementPermissionText(uint16_t collision, uint16_t elevation);
|
||||
QString getMetatileDisplayMessage(uint16_t metatileId);
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ private slots:
|
|||
void on_action_Reload_Project_triggered();
|
||||
void on_action_Close_Project_triggered();
|
||||
void on_action_Save_Project_triggered();
|
||||
void save(bool currentOnly = false);
|
||||
bool save(bool currentOnly = false);
|
||||
|
||||
void openEventMap(Event *event);
|
||||
|
||||
|
|
@ -242,8 +242,6 @@ private slots:
|
|||
void on_pushButton_AddConnection_clicked();
|
||||
void on_button_OpenDiveMap_clicked();
|
||||
void on_button_OpenEmergeMap_clicked();
|
||||
void on_comboBox_DiveMap_currentTextChanged(const QString &mapName);
|
||||
void on_comboBox_EmergeMap_currentTextChanged(const QString &mapName);
|
||||
void on_comboBox_PrimaryTileset_currentTextChanged(const QString &arg1);
|
||||
void on_comboBox_SecondaryTileset_currentTextChanged(const QString &arg1);
|
||||
void on_pushButton_ChangeDimensions_clicked();
|
||||
|
|
|
|||
|
|
@ -108,10 +108,6 @@ public:
|
|||
bool loadBlockdata(Layout *);
|
||||
bool loadLayoutBorder(Layout *);
|
||||
|
||||
void saveTextFile(QString path, QString text);
|
||||
void appendTextFile(QString path, QString text);
|
||||
void deleteFile(QString path);
|
||||
|
||||
bool readMapGroups();
|
||||
void addNewMapGroup(const QString &groupName);
|
||||
QString mapNameToMapGroup(const QString &mapName) const;
|
||||
|
|
@ -168,25 +164,20 @@ public:
|
|||
bool loadLayout(Layout *);
|
||||
bool loadMapLayout(Map*);
|
||||
bool loadLayoutTilesets(Layout *);
|
||||
void loadTilesetAssets(Tileset*);
|
||||
bool loadTilesetAssets(Tileset*);
|
||||
void loadTilesetMetatileLabels(Tileset*);
|
||||
void readTilesetPaths(Tileset* tileset);
|
||||
|
||||
void saveAll();
|
||||
void saveGlobalData();
|
||||
void saveLayout(Layout *);
|
||||
void saveLayoutBlockdata(Layout *);
|
||||
void saveLayoutBorder(Layout *);
|
||||
void writeBlockdata(QString, const Blockdata &);
|
||||
void saveMap(Map *map, bool skipLayout = false);
|
||||
void saveConfig();
|
||||
void saveMapLayouts();
|
||||
void saveMapGroups();
|
||||
void saveRegionMapSections();
|
||||
void saveWildMonData();
|
||||
void saveHealLocations();
|
||||
void saveTilesets(Tileset*, Tileset*);
|
||||
void saveTilesetMetatileLabels(Tileset*, Tileset*);
|
||||
bool saveAll();
|
||||
bool saveGlobalData();
|
||||
bool saveConfig();
|
||||
bool saveLayout(Layout *layout);
|
||||
bool saveMap(Map *map, bool skipLayout = false);
|
||||
bool saveTextFile(const QString &path, const QString &text);
|
||||
bool saveRegionMapSections();
|
||||
bool saveTilesets(Tileset*, Tileset*);
|
||||
bool saveTilesetMetatileLabels(Tileset*, Tileset*);
|
||||
|
||||
void appendTilesetLabel(const QString &label, const QString &isSecondaryStr);
|
||||
bool readTilesetLabels();
|
||||
bool readTilesetMetatileLabels();
|
||||
|
|
@ -235,30 +226,34 @@ public:
|
|||
|
||||
static QString getExistingFilepath(QString filepath);
|
||||
void applyParsedLimits();
|
||||
|
||||
|
||||
void setRegionMapEntries(const QHash<QString, MapSectionEntry> &entries);
|
||||
QHash<QString, MapSectionEntry> getRegionMapEntries() const;
|
||||
|
||||
QSet<QString> getTopLevelMapFields() const;
|
||||
|
||||
int getMapDataSize(int width, int height) const;
|
||||
int getMaxMapDataSize() const { return this->maxMapDataSize; }
|
||||
int getMaxMapWidth() const;
|
||||
int getMaxMapHeight() const;
|
||||
bool mapDimensionsValid(int width, int height) const;
|
||||
bool calculateDefaultMapSize();
|
||||
QSize getDefaultMapSize() const { return this->defaultMapSize; }
|
||||
QSize getMapSizeAddition() const { return this->mapSizeAddition; }
|
||||
|
||||
int getMaxEvents(Event::Group group) const;
|
||||
|
||||
static QString getEmptyMapDefineName();
|
||||
static QString getDynamicMapDefineName();
|
||||
static QString getDynamicMapName();
|
||||
static QString getEmptySpeciesName();
|
||||
static int getNumTilesPrimary();
|
||||
static int getNumTilesTotal();
|
||||
static int getNumMetatilesPrimary();
|
||||
static int getNumMetatilesTotal();
|
||||
static int getNumPalettesPrimary();
|
||||
static int getNumPalettesTotal();
|
||||
static int getMaxMapDataSize();
|
||||
static int getDefaultMapDimension();
|
||||
static int getMaxMapWidth();
|
||||
static int getMaxMapHeight();
|
||||
static int getMapDataSize(int width, int height);
|
||||
static bool mapDimensionsValid(int width, int height);
|
||||
bool calculateDefaultMapSize();
|
||||
int getMaxEvents(Event::Group group);
|
||||
static QMargins getMetatileViewDistance();
|
||||
static int getNumTilesPrimary() { return num_tiles_primary; }
|
||||
static int getNumTilesTotal() { return num_tiles_total; }
|
||||
static int getNumMetatilesPrimary() { return num_metatiles_primary; }
|
||||
static int getNumMetatilesTotal() { return Block::getMaxMetatileId() + 1; }
|
||||
static int getNumPalettesPrimary(){ return num_pals_primary; }
|
||||
static int getNumPalettesTotal() { return num_pals_total; }
|
||||
static QString getEmptyMapsecName();
|
||||
static QString getMapGroupPrefix();
|
||||
|
||||
|
|
@ -309,8 +304,6 @@ private:
|
|||
};
|
||||
QHash<QString, LocationData> locationData;
|
||||
|
||||
void updateLayout(Layout *);
|
||||
|
||||
void setNewLayoutBlockdata(Layout *layout);
|
||||
void setNewLayoutBorder(Layout *layout);
|
||||
|
||||
|
|
@ -318,17 +311,27 @@ private:
|
|||
void recordFileChange(const QString &filepath);
|
||||
void resetFileCache();
|
||||
|
||||
bool saveMapLayouts();
|
||||
bool saveMapGroups();
|
||||
bool saveWildMonData();
|
||||
bool saveHealLocations();
|
||||
bool appendTextFile(const QString &path, const QString &text);
|
||||
|
||||
QString findSpeciesIconPath(const QStringList &names) const;
|
||||
|
||||
int maxEventsPerGroup;
|
||||
int maxObjectEvents;
|
||||
int maxMapDataSize;
|
||||
QSize defaultMapSize;
|
||||
QSize mapSizeAddition;
|
||||
|
||||
// TODO: These really shouldn't be static, they're specific to a single project.
|
||||
// We're making an assumption here that we only have one project open at a single time
|
||||
// (which is true, but then if that's the case we should have some global Project instance instead)
|
||||
static int num_tiles_primary;
|
||||
static int num_tiles_total;
|
||||
static int num_metatiles_primary;
|
||||
static int num_pals_primary;
|
||||
static int num_pals_total;
|
||||
static int max_map_data_size;
|
||||
static int default_map_dimension;
|
||||
|
||||
signals:
|
||||
void fileChanged(const QString &filepath);
|
||||
|
|
|
|||
|
|
@ -43,8 +43,6 @@ protected:
|
|||
virtual void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*) override;
|
||||
virtual void keyPressEvent(QKeyEvent*) override;
|
||||
virtual void focusInEvent(QFocusEvent*) override;
|
||||
|
||||
signals:
|
||||
void connectionItemDoubleClicked(MapConnection*);
|
||||
|
|
|
|||
|
|
@ -36,19 +36,17 @@ private:
|
|||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent*) override;
|
||||
virtual void focusInEvent(QFocusEvent*) override;
|
||||
virtual void keyPressEvent(QKeyEvent*) override;
|
||||
virtual bool eventFilter(QObject*, QEvent *event) override;
|
||||
|
||||
signals:
|
||||
void selected();
|
||||
void openMapClicked(MapConnection*);
|
||||
|
||||
private slots:
|
||||
void on_comboBox_Direction_currentTextChanged(QString direction);
|
||||
void on_comboBox_Map_currentTextChanged(QString mapName);
|
||||
void on_spinBox_Offset_valueChanged(int offset);
|
||||
void on_button_Delete_clicked();
|
||||
void on_button_OpenMap_clicked();
|
||||
private:
|
||||
void commitDirection();
|
||||
void commitMap(const QString &mapName);
|
||||
void commitMove(int offset);
|
||||
void commitRemove();
|
||||
};
|
||||
|
||||
#endif // CONNECTIONSLISTITEM_H
|
||||
|
|
|
|||
|
|
@ -32,4 +32,17 @@ signals:
|
|||
void clicked(QMouseEvent *event);
|
||||
};
|
||||
|
||||
class ConnectionsView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConnectionsView(QWidget *parent = nullptr) : QGraphicsView(parent) {}
|
||||
|
||||
signals:
|
||||
void pressedDelete();
|
||||
|
||||
protected:
|
||||
virtual void keyPressEvent(QKeyEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // GRAPHICSVIEW_H
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ private:
|
|||
QPointer<Project> m_project = nullptr;
|
||||
bool m_allowProjectChanges = true;
|
||||
|
||||
void setText(QComboBox *combo, const QString &text) const;
|
||||
void setText(QLineEdit *lineEdit, const QString &text) const;
|
||||
void setLocations(const QStringList &locations);
|
||||
void updateLocationName();
|
||||
|
||||
|
|
|
|||
|
|
@ -10,27 +10,28 @@
|
|||
class MovableRect : public QGraphicsRectItem
|
||||
{
|
||||
public:
|
||||
MovableRect(bool *enabled, int width, int height, QRgb color);
|
||||
MovableRect(bool *enabled, const QRectF &rect, const QRgb &color);
|
||||
QRectF boundingRect() const override {
|
||||
qreal penWidth = 4;
|
||||
return QRectF(-penWidth,
|
||||
-penWidth,
|
||||
30 * 8 + penWidth * 2,
|
||||
20 * 8 + penWidth * 2);
|
||||
this->rect().width() + penWidth * 2,
|
||||
this->rect().height() + penWidth * 2);
|
||||
}
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override {
|
||||
if (!(*enabled)) return;
|
||||
painter->setPen(this->color);
|
||||
painter->drawRect(this->rect().x() - 2, this->rect().y() - 2, this->rect().width() + 3, this->rect().height() + 3);
|
||||
painter->setPen(QColor(0, 0, 0));
|
||||
painter->drawRect(this->rect().x() - 3, this->rect().y() - 3, this->rect().width() + 5, this->rect().height() + 5);
|
||||
painter->drawRect(this->rect().x() - 1, this->rect().y() - 1, this->rect().width() + 1, this->rect().height() + 1);
|
||||
painter->drawRect(this->rect() + QMargins(1,1,1,1)); // Fill
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawRect(this->rect() + QMargins(2,2,2,2)); // Outer border
|
||||
painter->drawRect(this->rect()); // Inner border
|
||||
}
|
||||
void updateLocation(int x, int y);
|
||||
bool *enabled;
|
||||
|
||||
protected:
|
||||
QRectF baseRect;
|
||||
QRgb color;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,13 +20,16 @@ public:
|
|||
virtual void accept() override;
|
||||
|
||||
signals:
|
||||
void accepted(MapConnection *result);
|
||||
void newConnectionedAdded(const QString &mapName, const QString &direction);
|
||||
void connectionReplaced(const QString &mapName, const QString &direction);
|
||||
|
||||
private:
|
||||
Ui::NewMapConnectionDialog *ui;
|
||||
Map *m_map;
|
||||
|
||||
bool mapNameIsValid();
|
||||
void setWarningVisible(bool visible);
|
||||
bool askReplaceConnection(MapConnection *connection, const QString &newMapName);
|
||||
};
|
||||
|
||||
#endif // NEWMAPCONNECTIONDIALOG_H
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ public:
|
|||
void setLineEdit(QLineEdit *edit);
|
||||
void setFocusedScrollingEnabled(bool enabled);
|
||||
|
||||
signals:
|
||||
void editingFinished();
|
||||
|
||||
private:
|
||||
void setItem(int index, const QString &text);
|
||||
|
||||
|
|
|
|||
25
include/ui/noscrolltextedit.h
Normal file
25
include/ui/noscrolltextedit.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef NOSCROLLTEXTEDIT_H
|
||||
#define NOSCROLLTEXTEDIT_H
|
||||
|
||||
#include <QTextEdit>
|
||||
#include <QWheelEvent>
|
||||
|
||||
class NoScrollTextEdit : public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NoScrollTextEdit(const QString &text, QWidget *parent = nullptr) : QTextEdit(text, parent) {
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
};
|
||||
explicit NoScrollTextEdit(QWidget *parent = nullptr) : NoScrollTextEdit(QString(), parent) {};
|
||||
|
||||
virtual void wheelEvent(QWheelEvent *event) override {
|
||||
if (hasFocus()) {
|
||||
QTextEdit::wheelEvent(event);
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif // NOSCROLLTEXTEDIT_H
|
||||
|
|
@ -149,10 +149,10 @@ public:
|
|||
void select(unsigned tileId);
|
||||
unsigned selectedTile = 0;
|
||||
|
||||
void selectVFlip(bool hFlip) { this->tile_hFlip = hFlip; }
|
||||
void selectHFlip(bool hFlip) { this->tile_hFlip = hFlip; }
|
||||
bool tile_hFlip = false;
|
||||
|
||||
void selectHFlip(bool vFlip) { this->tile_vFlip = vFlip; }
|
||||
void selectVFlip(bool vFlip) { this->tile_vFlip = vFlip; }
|
||||
bool tile_vFlip = false;
|
||||
|
||||
void selectPalette(int palette) {
|
||||
|
|
|
|||
|
|
@ -71,8 +71,6 @@ private slots:
|
|||
|
||||
void on_spinBox_paletteSelector_valueChanged(int arg1);
|
||||
|
||||
void on_actionSave_Tileset_triggered();
|
||||
|
||||
void on_actionImport_Primary_Tiles_triggered();
|
||||
|
||||
void on_actionImport_Secondary_Tiles_triggered();
|
||||
|
|
@ -173,6 +171,8 @@ private:
|
|||
bool lockSelection = false;
|
||||
QSet<uint16_t> metatileReloadQueue;
|
||||
|
||||
bool save();
|
||||
|
||||
signals:
|
||||
void tilesetsSaved(QString, QString);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ HEADERS += include/core/advancemapparser.h \
|
|||
include/ui/newmapgroupdialog.h \
|
||||
include/ui/noscrollcombobox.h \
|
||||
include/ui/noscrollspinbox.h \
|
||||
include/ui/noscrolltextedit.h \
|
||||
include/ui/montabwidget.h \
|
||||
include/ui/encountertablemodel.h \
|
||||
include/ui/encountertabledelegates.h \
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@
|
|||
#include <QAction>
|
||||
#include <QAbstractButton>
|
||||
|
||||
const QVersionNumber porymapVersion = QVersionNumber::fromString(PORYMAP_VERSION);
|
||||
|
||||
// In both versions the default new map border is a generic tree
|
||||
const QList<uint16_t> defaultBorder_RSE = {0x1D4, 0x1D5, 0x1DC, 0x1DD};
|
||||
const QList<uint16_t> defaultBorder_FRLG = {0x14, 0x15, 0x1C, 0x1D};
|
||||
|
||||
const QList<uint32_t> defaultWarpBehaviors_RSE = {
|
||||
0x0E, // MB_MOSSDEEP_GYM_WARP
|
||||
0x0F, // MB_MT_PYRE_HOLE
|
||||
|
|
@ -89,6 +95,8 @@ const QMap<ProjectIdentifier, QPair<QString, QString>> ProjectConfig::defaultIde
|
|||
{ProjectIdentifier::define_pals_total, {"define_pals_total", "NUM_PALS_TOTAL"}},
|
||||
{ProjectIdentifier::define_tiles_per_metatile, {"define_tiles_per_metatile", "NUM_TILES_PER_METATILE"}},
|
||||
{ProjectIdentifier::define_map_size, {"define_map_size", "MAX_MAP_DATA_SIZE"}},
|
||||
{ProjectIdentifier::define_map_offset_width, {"define_map_offset_width", "MAP_OFFSET_W"}},
|
||||
{ProjectIdentifier::define_map_offset_height, {"define_map_offset_height", "MAP_OFFSET_H"}},
|
||||
{ProjectIdentifier::define_mask_metatile, {"define_mask_metatile", "MAPGRID_METATILE_ID_MASK"}},
|
||||
{ProjectIdentifier::define_mask_collision, {"define_mask_collision", "MAPGRID_COLLISION_MASK"}},
|
||||
{ProjectIdentifier::define_mask_elevation, {"define_mask_elevation", "MAPGRID_ELEVATION_MASK"}},
|
||||
|
|
@ -233,7 +241,7 @@ void KeyValueConfigBase::load() {
|
|||
file.close();
|
||||
}
|
||||
|
||||
void KeyValueConfigBase::save() {
|
||||
bool KeyValueConfigBase::save() {
|
||||
QString text = "";
|
||||
QMap<QString, QString> map = this->getKeyValueMap();
|
||||
for (QMap<QString, QString>::iterator it = map.begin(); it != map.end(); it++) {
|
||||
|
|
@ -241,15 +249,17 @@ void KeyValueConfigBase::save() {
|
|||
}
|
||||
|
||||
QFile file(this->getConfigFilepath());
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(text.toUtf8());
|
||||
file.close();
|
||||
} else {
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Could not open config file '%1' for writing: ").arg(this->getConfigFilepath()) + file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
file.write(text.toUtf8());
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyValueConfigBase::getConfigBool(QString key, QString value) {
|
||||
bool KeyValueConfigBase::getConfigBool(const QString &key, const QString &value) {
|
||||
bool ok;
|
||||
int result = value.toInt(&ok, 0);
|
||||
if (!ok || (result != 0 && result != 1)) {
|
||||
|
|
@ -258,26 +268,35 @@ bool KeyValueConfigBase::getConfigBool(QString key, QString value) {
|
|||
return (result != 0);
|
||||
}
|
||||
|
||||
int KeyValueConfigBase::getConfigInteger(QString key, QString value, int min, int max, int defaultValue) {
|
||||
int KeyValueConfigBase::getConfigInteger(const QString &key, const QString &value, int min, int max, int defaultValue) {
|
||||
bool ok;
|
||||
int result = value.toInt(&ok, 0);
|
||||
if (!ok) {
|
||||
logWarn(QString("Invalid config value for %1: '%2'. Must be an integer.").arg(key).arg(value));
|
||||
return defaultValue;
|
||||
logWarn(QString("Invalid config value for %1: '%2'. Must be an integer. Using default value '%3'.").arg(key).arg(value).arg(defaultValue));
|
||||
result = defaultValue;
|
||||
}
|
||||
return qMin(max, qMax(min, result));
|
||||
}
|
||||
|
||||
uint32_t KeyValueConfigBase::getConfigUint32(QString key, QString value, uint32_t min, uint32_t max, uint32_t defaultValue) {
|
||||
uint32_t KeyValueConfigBase::getConfigUint32(const QString &key, const QString &value, uint32_t min, uint32_t max, uint32_t defaultValue) {
|
||||
bool ok;
|
||||
uint32_t result = value.toUInt(&ok, 0);
|
||||
if (!ok) {
|
||||
logWarn(QString("Invalid config value for %1: '%2'. Must be an integer.").arg(key).arg(value));
|
||||
return defaultValue;
|
||||
logWarn(QString("Invalid config value for %1: '%2'. Must be an integer. Using default value '%3'.").arg(key).arg(value).arg(defaultValue));
|
||||
result = defaultValue;
|
||||
}
|
||||
return qMin(max, qMax(min, result));
|
||||
}
|
||||
|
||||
QColor KeyValueConfigBase::getConfigColor(const QString &key, const QString &value, const QColor &defaultValue) {
|
||||
QColor color = QColor("#" + value);
|
||||
if (!color.isValid()) {
|
||||
logWarn(QString("Invalid config value for %1: '%2'. Must be a color in the format 'RRGGBB'. Using default value '%3'.").arg(key).arg(value).arg(defaultValue.name()));
|
||||
color = defaultValue;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
PorymapConfig porymapConfig;
|
||||
|
||||
QString PorymapConfig::getConfigFilepath() {
|
||||
|
|
@ -445,6 +464,18 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
}
|
||||
} else if (key == "shown_in_game_reload_message") {
|
||||
this->shownInGameReloadMessage = getConfigBool(key, value);
|
||||
} else if (key == "grid_width") {
|
||||
this->gridSettings.width = getConfigUint32(key, value);
|
||||
} else if (key == "grid_height") {
|
||||
this->gridSettings.height = getConfigUint32(key, value);
|
||||
} else if (key == "grid_x") {
|
||||
this->gridSettings.offsetX = getConfigInteger(key, value, 0, 999);
|
||||
} else if (key == "grid_y") {
|
||||
this->gridSettings.offsetY = getConfigInteger(key, value, 0, 999);
|
||||
} else if (key == "grid_style") {
|
||||
this->gridSettings.style = GridSettings::getStyleFromName(value);
|
||||
} else if (key == "grid_color") {
|
||||
this->gridSettings.color = getConfigColor(key, value);
|
||||
} else {
|
||||
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
|
||||
}
|
||||
|
|
@ -522,6 +553,12 @@ QMap<QString, QString> PorymapConfig::getKeyValueMap() {
|
|||
}
|
||||
map.insert("event_selection_shape_mode", (this->eventSelectionShapeMode == QGraphicsPixmapItem::MaskShape) ? "mask" : "bounding_rect");
|
||||
map.insert("shown_in_game_reload_message", this->shownInGameReloadMessage ? "1" : "0");
|
||||
map.insert("grid_width", QString::number(this->gridSettings.width));
|
||||
map.insert("grid_height", QString::number(this->gridSettings.height));
|
||||
map.insert("grid_x", QString::number(this->gridSettings.offsetX));
|
||||
map.insert("grid_y", QString::number(this->gridSettings.offsetY));
|
||||
map.insert("grid_style", GridSettings::getStyleName(this->gridSettings.style));
|
||||
map.insert("grid_color", this->gridSettings.color.name().remove("#")); // Our text config treats '#' as the start of a comment.
|
||||
|
||||
return map;
|
||||
}
|
||||
|
|
@ -737,6 +774,10 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
this->defaultElevation = getConfigUint32(key, value, 0, Block::maxValue);
|
||||
} else if (key == "default_collision") {
|
||||
this->defaultCollision = getConfigUint32(key, value, 0, Block::maxValue);
|
||||
} else if (key == "default_map_width") {
|
||||
this->defaultMapSize.setWidth(getConfigInteger(key, value, 1));
|
||||
} else if (key == "default_map_height") {
|
||||
this->defaultMapSize.setHeight(getConfigInteger(key, value, 1));
|
||||
} else if (key == "new_map_border_metatiles") {
|
||||
this->newMapBorderMetatileIds.clear();
|
||||
QList<QString> metatileIds = value.split(",");
|
||||
|
|
@ -826,9 +867,17 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
} else if (key == "collision_sheet_path") {
|
||||
this->collisionSheetPath = value;
|
||||
} else if (key == "collision_sheet_width") {
|
||||
this->collisionSheetWidth = getConfigUint32(key, value, 1, Block::maxValue);
|
||||
this->collisionSheetSize.setWidth(getConfigInteger(key, value, 1, Block::maxValue));
|
||||
} else if (key == "collision_sheet_height") {
|
||||
this->collisionSheetHeight = getConfigUint32(key, value, 1, Block::maxValue);
|
||||
this->collisionSheetSize.setHeight(getConfigInteger(key, value, 1, Block::maxValue));
|
||||
} else if (key == "player_view_north") {
|
||||
this->playerViewDistance.setTop(getConfigInteger(key, value, 0, INT_MAX, GBA_V_DIST_TO_CENTER));
|
||||
} else if (key == "player_view_south") {
|
||||
this->playerViewDistance.setBottom(getConfigInteger(key, value, 0, INT_MAX, GBA_V_DIST_TO_CENTER));
|
||||
} else if (key == "player_view_west") {
|
||||
this->playerViewDistance.setLeft(getConfigInteger(key, value, 0, INT_MAX, GBA_H_DIST_TO_CENTER));
|
||||
} else if (key == "player_view_east") {
|
||||
this->playerViewDistance.setRight(getConfigInteger(key, value, 0, INT_MAX, GBA_H_DIST_TO_CENTER));
|
||||
} else if (key == "warp_behaviors") {
|
||||
this->warpBehaviors.clear();
|
||||
value.remove(" ");
|
||||
|
|
@ -862,7 +911,7 @@ void ProjectConfig::setUnreadKeys() {
|
|||
if (!readKeys.contains("enable_event_clone_object")) this->eventCloneObjectEnabled = isPokefirered;
|
||||
if (!readKeys.contains("enable_floor_number")) this->floorNumberEnabled = isPokefirered;
|
||||
if (!readKeys.contains("create_map_text_file")) this->createMapTextFileEnabled = (this->baseGameVersion != BaseGameVersion::pokeemerald);
|
||||
if (!readKeys.contains("new_map_border_metatiles")) this->newMapBorderMetatileIds = isPokefirered ? DEFAULT_BORDER_FRLG : DEFAULT_BORDER_RSE;
|
||||
if (!readKeys.contains("new_map_border_metatiles")) this->newMapBorderMetatileIds = isPokefirered ? defaultBorder_FRLG : defaultBorder_RSE;
|
||||
if (!readKeys.contains("default_secondary_tileset")) this->defaultSecondaryTileset = isPokefirered ? "gTileset_PalletTown" : "gTileset_Petalburg";
|
||||
if (!readKeys.contains("metatile_attributes_size")) this->metatileAttributesSize = Metatile::getDefaultAttributesSize(this->baseGameVersion);
|
||||
if (!readKeys.contains("metatile_behavior_mask")) this->metatileBehaviorMask = Metatile::getDefaultAttributesMask(this->baseGameVersion, Metatile::Attr::Behavior);
|
||||
|
|
@ -890,6 +939,8 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
|
|||
map.insert("default_metatile", Metatile::getMetatileIdString(this->defaultMetatileId));
|
||||
map.insert("default_elevation", QString::number(this->defaultElevation));
|
||||
map.insert("default_collision", QString::number(this->defaultCollision));
|
||||
map.insert("default_map_width", QString::number(this->defaultMapSize.width()));
|
||||
map.insert("default_map_height", QString::number(this->defaultMapSize.height()));
|
||||
map.insert("new_map_border_metatiles", Metatile::getMetatileIdStrings(this->newMapBorderMetatileIds));
|
||||
map.insert("default_primary_tileset", this->defaultPrimaryTileset);
|
||||
map.insert("default_secondary_tileset", this->defaultSecondaryTileset);
|
||||
|
|
@ -927,8 +978,12 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
|
|||
map.insert("ident/"+defaultIdentifiers.value(i.key()).first, i.value());
|
||||
}
|
||||
map.insert("collision_sheet_path", this->collisionSheetPath);
|
||||
map.insert("collision_sheet_width", QString::number(this->collisionSheetWidth));
|
||||
map.insert("collision_sheet_height", QString::number(this->collisionSheetHeight));
|
||||
map.insert("collision_sheet_width", QString::number(this->collisionSheetSize.width()));
|
||||
map.insert("collision_sheet_height", QString::number(this->collisionSheetSize.height()));
|
||||
map.insert("player_view_north", QString::number(this->playerViewDistance.top()));
|
||||
map.insert("player_view_south", QString::number(this->playerViewDistance.bottom()));
|
||||
map.insert("player_view_west", QString::number(this->playerViewDistance.left()));
|
||||
map.insert("player_view_east", QString::number(this->playerViewDistance.right()));
|
||||
QStringList warpBehaviorStrs;
|
||||
for (const auto &value : this->warpBehaviors)
|
||||
warpBehaviorStrs.append("0x" + QString("%1").arg(value, 2, 16, QChar('0')).toUpper());
|
||||
|
|
|
|||
|
|
@ -777,6 +777,7 @@ Event *HealLocationEvent::duplicate() const {
|
|||
copy->setX(this->getX());
|
||||
copy->setY(this->getY());
|
||||
copy->setIdName(this->getIdName());
|
||||
copy->setHostMapName(this->getHostMapName());
|
||||
copy->setRespawnMapName(this->getRespawnMapName());
|
||||
copy->setRespawnNPC(this->getRespawnNPC());
|
||||
|
||||
|
|
|
|||
|
|
@ -83,16 +83,17 @@ QRect Map::getConnectionRect(const QString &direction, Layout * fromLayout) cons
|
|||
int x = 0, y = 0;
|
||||
int w = getWidth(), h = getHeight();
|
||||
|
||||
QMargins viewDistance = Project::getMetatileViewDistance();
|
||||
if (direction == "up") {
|
||||
h = qMin(h, BORDER_DISTANCE);
|
||||
h = qMin(h, viewDistance.top());
|
||||
y = getHeight() - h;
|
||||
} else if (direction == "down") {
|
||||
h = qMin(h, BORDER_DISTANCE);
|
||||
h = qMin(h, viewDistance.bottom());
|
||||
} else if (direction == "left") {
|
||||
w = qMin(w, BORDER_DISTANCE);
|
||||
w = qMin(w, viewDistance.left());
|
||||
x = getWidth() - w;
|
||||
} else if (direction == "right") {
|
||||
w = qMin(w, BORDER_DISTANCE);
|
||||
w = qMin(w, viewDistance.right());
|
||||
} else if (MapConnection::isDiving(direction)) {
|
||||
if (fromLayout) {
|
||||
w = qMin(w, fromLayout->getWidth());
|
||||
|
|
@ -331,6 +332,15 @@ void Map::removeConnection(MapConnection *connection) {
|
|||
emit connectionRemoved(connection);
|
||||
}
|
||||
|
||||
// Return the first map connection that has the given direction.
|
||||
MapConnection* Map::getConnection(const QString &direction) const {
|
||||
for (const auto &connection : m_connections) {
|
||||
if (connection->direction() == direction)
|
||||
return connection;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Map::commit(QUndoCommand *cmd) {
|
||||
m_editHistory->push(cmd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,17 +63,11 @@ bool Layout::isWithinBorderBounds(int x, int y) const {
|
|||
return (x >= 0 && x < this->getBorderWidth() && y >= 0 && y < this->getBorderHeight());
|
||||
}
|
||||
|
||||
int Layout::getBorderDrawWidth() const {
|
||||
return getBorderDrawDistance(border_width, BORDER_DISTANCE);
|
||||
}
|
||||
|
||||
int Layout::getBorderDrawHeight() const {
|
||||
return getBorderDrawDistance(border_height, BORDER_DISTANCE);
|
||||
}
|
||||
|
||||
// We need to draw sufficient border blocks to fill the area that gets loaded around the player in-game (BORDER_DISTANCE).
|
||||
// Note that this is not the same as the player's view distance.
|
||||
// The result will be some multiple of the input dimension, because we only draw the border in increments of its full width/height.
|
||||
// Calculate the distance away from the layout's edge that we need to start drawing border blocks.
|
||||
// We need to fulfill two requirements here:
|
||||
// - We should draw enough to fill the player's in-game view
|
||||
// - The value should be some multiple of the border's dimension
|
||||
// (otherwise the border won't be positioned the same as it would in-game).
|
||||
int Layout::getBorderDrawDistance(int dimension, qreal minimum) {
|
||||
if (dimension >= minimum)
|
||||
return dimension;
|
||||
|
|
@ -81,6 +75,23 @@ int Layout::getBorderDrawDistance(int dimension, qreal minimum) {
|
|||
// Get first multiple of dimension >= the minimum
|
||||
return dimension * qCeil(minimum / qMax(dimension, 1));
|
||||
}
|
||||
QMargins Layout::getBorderMargins() const {
|
||||
QMargins minimum = Project::getMetatileViewDistance();
|
||||
QMargins distance;
|
||||
distance.setTop(getBorderDrawDistance(this->border_height, minimum.top()));
|
||||
distance.setBottom(getBorderDrawDistance(this->border_height, minimum.bottom()));
|
||||
distance.setLeft(getBorderDrawDistance(this->border_width, minimum.left()));
|
||||
distance.setRight(getBorderDrawDistance(this->border_width, minimum.right()));
|
||||
return distance;
|
||||
}
|
||||
|
||||
// Get a rectangle that represents (in pixels) the layout's map area and the visible area of its border.
|
||||
// At maximum, this is equal to the map size plus the border margins.
|
||||
// If the border is large (and so beyond player the view) it may be smaller than that.
|
||||
QRect Layout::getVisibleRect() const {
|
||||
QRect area = QRect(0, 0, this->width * 16, this->height * 16);
|
||||
return area += (Project::getMetatileViewDistance() * 16);
|
||||
}
|
||||
|
||||
bool Layout::getBlock(int x, int y, Block *out) {
|
||||
if (isWithinBounds(x, y)) {
|
||||
|
|
@ -467,11 +478,50 @@ QPixmap Layout::getLayoutItemPixmap() {
|
|||
return this->layoutItem ? this->layoutItem->pixmap() : QPixmap();
|
||||
}
|
||||
|
||||
void Layout::setClean() {
|
||||
this->editHistory.setClean();
|
||||
this->hasUnsavedDataChanges = false;
|
||||
}
|
||||
|
||||
bool Layout::hasUnsavedChanges() const {
|
||||
return !this->editHistory.isClean() || this->hasUnsavedDataChanges || !this->newFolderPath.isEmpty();
|
||||
}
|
||||
|
||||
bool Layout::save(const QString &root) {
|
||||
if (!this->newFolderPath.isEmpty()) {
|
||||
// Layout directory doesn't exist yet, create it now.
|
||||
const QString fullPath = QString("%1/%2").arg(root).arg(this->newFolderPath);
|
||||
if (!QDir::root().mkpath(fullPath)) {
|
||||
logError(QString("Failed to create directory for new layout: '%1'").arg(fullPath));
|
||||
return false;
|
||||
}
|
||||
this->newFolderPath = QString();
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
if (!saveBorder(root)) success = false;
|
||||
if (!saveBlockdata(root)) success = false;
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
this->editHistory.setClean();
|
||||
this->hasUnsavedDataChanges = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Layout::saveBorder(const QString &root) {
|
||||
QString path = QString("%1/%2").arg(root).arg(this->border_path);
|
||||
return writeBlockdata(path, this->border);
|
||||
}
|
||||
|
||||
bool Layout::saveBlockdata(const QString &root) {
|
||||
QString path = QString("%1/%2").arg(root).arg(this->blockdata_path);
|
||||
return writeBlockdata(path, this->blockdata);
|
||||
}
|
||||
|
||||
bool Layout::writeBlockdata(const QString &path, const Blockdata &blockdata) const {
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(path).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = blockdata.serialize();
|
||||
file.write(data);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ QList<QRgb> PaletteUtil::parse(QString filepath, bool *error) {
|
|||
return QList<QRgb>();
|
||||
}
|
||||
|
||||
void PaletteUtil::writeJASC(QString filepath, QVector<QRgb> palette, int offset, int nColors) {
|
||||
bool PaletteUtil::writeJASC(const QString &filepath, const QVector<QRgb> &palette, int offset, int nColors) {
|
||||
if (!nColors) {
|
||||
logWarn(QString("Cannot save a palette with no colors."));
|
||||
return;
|
||||
logError(QString("Cannot save a palette with no colors."));
|
||||
return false;
|
||||
}
|
||||
if (offset > palette.size() || offset + nColors > palette.size()) {
|
||||
logWarn("Palette offset out of range for color table.");
|
||||
return;
|
||||
logError("Palette offset out of range for color table.");
|
||||
return false;
|
||||
}
|
||||
|
||||
QString text = "JASC-PAL\r\n0100\r\n";
|
||||
|
|
@ -59,11 +59,13 @@ void PaletteUtil::writeJASC(QString filepath, QVector<QRgb> palette, int offset,
|
|||
}
|
||||
|
||||
QFile file(filepath);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(text.toUtf8());
|
||||
} else {
|
||||
logWarn(QString("Could not write to file '%1': ").arg(filepath) + file.errorString());
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Could not write to file '%1': ").arg(filepath) + file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
file.write(text.toUtf8());
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QRgb> parsePal(QString filepath, bool *error) {
|
||||
|
|
|
|||
|
|
@ -402,13 +402,13 @@ QHash<int, QString> Tileset::getHeaderMemberMap(bool usingAsm)
|
|||
return map;
|
||||
}
|
||||
|
||||
void Tileset::loadMetatiles() {
|
||||
bool Tileset::loadMetatiles() {
|
||||
clearMetatiles();
|
||||
|
||||
QFile metatiles_file(this->metatiles_path);
|
||||
if (!metatiles_file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading.").arg(this->metatiles_path));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatiles_path).arg(metatiles_file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = metatiles_file.readAll();
|
||||
|
|
@ -425,13 +425,14 @@ void Tileset::loadMetatiles() {
|
|||
}
|
||||
m_metatiles.append(metatile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tileset::saveMetatiles() {
|
||||
bool Tileset::saveMetatiles() {
|
||||
QFile metatiles_file(this->metatiles_path);
|
||||
if (!metatiles_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing.").arg(this->metatiles_path));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatiles_path).arg(metatiles_file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data;
|
||||
|
|
@ -444,13 +445,14 @@ void Tileset::saveMetatiles() {
|
|||
}
|
||||
}
|
||||
metatiles_file.write(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tileset::loadMetatileAttributes() {
|
||||
bool Tileset::loadMetatileAttributes() {
|
||||
QFile attrs_file(this->metatile_attrs_path);
|
||||
if (!attrs_file.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Could not open '%1' for reading.").arg(this->metatile_attrs_path));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for reading: %2").arg(this->metatile_attrs_path).arg(attrs_file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = attrs_file.readAll();
|
||||
|
|
@ -467,13 +469,14 @@ void Tileset::loadMetatileAttributes() {
|
|||
attributes |= static_cast<unsigned char>(data.at(i * attrSize + j)) << (8 * j);
|
||||
m_metatiles.at(i)->setAttributes(attributes);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tileset::saveMetatileAttributes() {
|
||||
bool Tileset::saveMetatileAttributes() {
|
||||
QFile attrs_file(this->metatile_attrs_path);
|
||||
if (!attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
logError(QString("Could not open '%1' for writing.").arg(this->metatile_attrs_path));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(this->metatile_attrs_path).arg(attrs_file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data;
|
||||
|
|
@ -483,9 +486,10 @@ void Tileset::saveMetatileAttributes() {
|
|||
data.append(static_cast<char>(attributes >> (8 * i)));
|
||||
}
|
||||
attrs_file.write(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tileset::loadTilesImage(QImage *importedImage) {
|
||||
bool Tileset::loadTilesImage(QImage *importedImage) {
|
||||
QImage image;
|
||||
if (importedImage) {
|
||||
image = *importedImage;
|
||||
|
|
@ -520,23 +524,25 @@ void Tileset::loadTilesImage(QImage *importedImage) {
|
|||
}
|
||||
this->tilesImage = image;
|
||||
this->tiles = tiles;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tileset::saveTilesImage() {
|
||||
bool Tileset::saveTilesImage() {
|
||||
// Only write the tiles image if it was changed.
|
||||
// Porymap will only ever change an existing tiles image by importing a new one.
|
||||
if (!m_hasUnsavedTilesImage)
|
||||
return;
|
||||
return true;
|
||||
|
||||
if (!this->tilesImage.save(this->tilesImagePath, "PNG")) {
|
||||
logError(QString("Failed to save tiles image '%1'").arg(this->tilesImagePath));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hasUnsavedTilesImage = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tileset::loadPalettes() {
|
||||
bool Tileset::loadPalettes() {
|
||||
this->palettes.clear();
|
||||
this->palettePreviews.clear();
|
||||
|
||||
|
|
@ -559,26 +565,34 @@ void Tileset::loadPalettes() {
|
|||
this->palettes.append(palette);
|
||||
this->palettePreviews.append(palette);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tileset::savePalettes() {
|
||||
bool Tileset::savePalettes() {
|
||||
bool success = true;
|
||||
int numPalettes = qMin(this->palettePaths.length(), this->palettes.length());
|
||||
for (int i = 0; i < numPalettes; i++) {
|
||||
PaletteUtil::writeJASC(this->palettePaths.at(i), this->palettes.at(i).toVector(), 0, 16);
|
||||
if (!PaletteUtil::writeJASC(this->palettePaths.at(i), this->palettes.at(i).toVector(), 0, 16))
|
||||
success = false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void Tileset::load() {
|
||||
loadMetatiles();
|
||||
loadMetatileAttributes();
|
||||
loadTilesImage();
|
||||
loadPalettes();
|
||||
bool Tileset::load() {
|
||||
bool success = true;
|
||||
if (!loadMetatiles()) success = false;
|
||||
if (!loadMetatileAttributes()) success = false;
|
||||
if (!loadTilesImage()) success = false;
|
||||
if (!loadPalettes()) success = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
// Because metatile labels are global (and handled by the project) we don't save them here.
|
||||
void Tileset::save() {
|
||||
saveMetatiles();
|
||||
saveMetatileAttributes();
|
||||
saveTilesImage();
|
||||
savePalettes();
|
||||
bool Tileset::save() {
|
||||
bool success = true;
|
||||
if (!saveMetatiles()) success = false;
|
||||
if (!saveMetatileAttributes()) success = false;
|
||||
if (!saveTilesImage()) success = false;
|
||||
if (!savePalettes()) success = false;
|
||||
return success;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ QString Util::toHexString(uint32_t value, int minLength) {
|
|||
return "0x" + QString("%1").arg(value, minLength, 16, QChar('0')).toUpper();
|
||||
}
|
||||
|
||||
QString Util::toHtmlParagraph(const QString &text) {
|
||||
return QString("<html><head/><body><p>%1</p></body></html>").arg(text);
|
||||
}
|
||||
|
||||
Qt::Orientations Util::getOrientation(bool xflip, bool yflip) {
|
||||
Qt::Orientations flags;
|
||||
if (xflip) flags |= Qt::Orientation::Horizontal;
|
||||
|
|
|
|||
138
src/editor.cpp
138
src/editor.cpp
|
|
@ -30,7 +30,6 @@ Editor::Editor(Ui::MainWindow* ui)
|
|||
{
|
||||
this->ui = ui;
|
||||
this->settings = new Settings();
|
||||
this->playerViewRect = new MovableRect(&this->settings->playerViewRectEnabled, 30 * 8, 20 * 8, qRgb(255, 255, 255));
|
||||
this->cursorMapTileRect = new CursorTileRect(&this->settings->cursorTileRectEnabled, qRgb(255, 255, 255));
|
||||
this->map_ruler = new MapRuler(4);
|
||||
connect(this->map_ruler, &MapRuler::statusChanged, this, &Editor::mapRulerStatusChanged);
|
||||
|
|
@ -54,6 +53,19 @@ Editor::Editor(Ui::MainWindow* ui)
|
|||
connect(ui->actionOpen_Project_in_Text_Editor, &QAction::triggered, this, &Editor::openProjectInTextEditor);
|
||||
connect(ui->checkBox_ToggleGrid, &QCheckBox::toggled, this, &Editor::toggleGrid);
|
||||
connect(ui->mapCustomAttributesFrame->table(), &CustomAttributesTable::edited, this, &Editor::updateCustomMapAttributes);
|
||||
|
||||
connect(ui->comboBox_DiveMap, &NoScrollComboBox::editingFinished, [this] {
|
||||
onDivingMapEditingFinished(this->ui->comboBox_DiveMap, "dive");
|
||||
});
|
||||
connect(ui->comboBox_EmergeMap, &NoScrollComboBox::editingFinished, [this] {
|
||||
onDivingMapEditingFinished(this->ui->comboBox_EmergeMap, "emerge");
|
||||
});
|
||||
connect(ui->comboBox_DiveMap, &NoScrollComboBox::currentTextChanged, [this] {
|
||||
updateDivingMapButton(this->ui->button_OpenDiveMap, this->ui->comboBox_DiveMap->currentText());
|
||||
});
|
||||
connect(ui->comboBox_EmergeMap, &NoScrollComboBox::currentTextChanged, [this] {
|
||||
updateDivingMapButton(this->ui->button_OpenEmergeMap, this->ui->comboBox_EmergeMap->currentText());
|
||||
});
|
||||
}
|
||||
|
||||
Editor::~Editor()
|
||||
|
|
@ -68,30 +80,33 @@ Editor::~Editor()
|
|||
closeProject();
|
||||
}
|
||||
|
||||
void Editor::saveCurrent() {
|
||||
save(true);
|
||||
bool Editor::saveCurrent() {
|
||||
return save(true);
|
||||
}
|
||||
|
||||
void Editor::saveAll() {
|
||||
save(false);
|
||||
bool Editor::saveAll() {
|
||||
return save(false);
|
||||
}
|
||||
|
||||
void Editor::save(bool currentOnly) {
|
||||
bool Editor::save(bool currentOnly) {
|
||||
if (!this->project)
|
||||
return;
|
||||
return true;
|
||||
|
||||
saveEncounterTabData();
|
||||
|
||||
bool success = true;
|
||||
if (currentOnly) {
|
||||
if (this->map) {
|
||||
this->project->saveMap(this->map);
|
||||
success = this->project->saveMap(this->map);
|
||||
} else if (this->layout) {
|
||||
this->project->saveLayout(this->layout);
|
||||
success = this->project->saveLayout(this->layout);
|
||||
}
|
||||
this->project->saveGlobalData();
|
||||
if (!this->project->saveGlobalData())
|
||||
success = false;
|
||||
} else {
|
||||
this->project->saveAll();
|
||||
success = this->project->saveAll();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void Editor::setProject(Project * project) {
|
||||
|
|
@ -805,23 +820,41 @@ void Editor::displayConnection(MapConnection *connection) {
|
|||
}
|
||||
}
|
||||
|
||||
void Editor::addConnection(MapConnection *connection) {
|
||||
if (!connection)
|
||||
void Editor::addNewConnection(const QString &mapName, const QString &direction) {
|
||||
if (!this->map)
|
||||
return;
|
||||
|
||||
MapConnection *connection = new MapConnection(mapName, direction);
|
||||
|
||||
// Mark this connection to be selected once its display elements have been created.
|
||||
// It's possible this is a Dive/Emerge connection, but that's ok (no selection will occur).
|
||||
connection_to_select = connection;
|
||||
this->connection_to_select = connection;
|
||||
|
||||
this->map->commit(new MapConnectionAdd(this->map, connection));
|
||||
}
|
||||
|
||||
void Editor::replaceConnection(const QString &mapName, const QString &direction) {
|
||||
if (!this->map)
|
||||
return;
|
||||
|
||||
MapConnection *connection = this->map->getConnection(direction);
|
||||
if (!connection || connection->targetMapName() == mapName)
|
||||
return;
|
||||
|
||||
this->map->commit(new MapConnectionChangeMap(connection, mapName));
|
||||
}
|
||||
|
||||
void Editor::removeConnection(MapConnection *connection) {
|
||||
if (!connection)
|
||||
if (!this->map || !connection)
|
||||
return;
|
||||
this->map->commit(new MapConnectionRemove(this->map, connection));
|
||||
}
|
||||
|
||||
void Editor::removeSelectedConnection() {
|
||||
if (selected_connection_item)
|
||||
removeConnection(selected_connection_item->connection);
|
||||
}
|
||||
|
||||
void Editor::removeConnectionPixmap(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
|
|
@ -914,21 +947,18 @@ void Editor::removeDivingMapPixmap(MapConnection *connection) {
|
|||
updateDivingMapsVisibility();
|
||||
}
|
||||
|
||||
void Editor::updateDiveMap(QString mapName) {
|
||||
setDivingMapName(mapName, "dive");
|
||||
}
|
||||
bool Editor::setDivingMapName(const QString &mapName, const QString &direction) {
|
||||
if (!mapName.isEmpty() && !this->project->mapNames.contains(mapName))
|
||||
return false;
|
||||
if (!MapConnection::isDiving(direction))
|
||||
return false;
|
||||
|
||||
void Editor::updateEmergeMap(QString mapName) {
|
||||
setDivingMapName(mapName, "emerge");
|
||||
}
|
||||
|
||||
void Editor::setDivingMapName(QString mapName, QString direction) {
|
||||
auto pixmapItem = diving_map_items.value(direction);
|
||||
MapConnection *connection = pixmapItem ? pixmapItem->connection() : nullptr;
|
||||
|
||||
if (connection) {
|
||||
if (mapName == connection->targetMapName())
|
||||
return; // No change
|
||||
return true; // No change
|
||||
|
||||
// Update existing connection
|
||||
if (mapName.isEmpty()) {
|
||||
|
|
@ -938,8 +968,25 @@ void Editor::setDivingMapName(QString mapName, QString direction) {
|
|||
}
|
||||
} else if (!mapName.isEmpty()) {
|
||||
// Create new connection
|
||||
addConnection(new MapConnection(mapName, direction));
|
||||
addNewConnection(mapName, direction);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString Editor::getDivingMapName(const QString &direction) const {
|
||||
auto pixmapItem = diving_map_items.value(direction);
|
||||
return (pixmapItem && pixmapItem->connection()) ? pixmapItem->connection()->targetMapName() : QString();
|
||||
}
|
||||
|
||||
void Editor::onDivingMapEditingFinished(NoScrollComboBox *combo, const QString &direction) {
|
||||
if (!setDivingMapName(combo->currentText(), direction)) {
|
||||
// If user input was invalid, restore the combo to the previously-valid text.
|
||||
combo->setCurrentText(getDivingMapName(direction));
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::updateDivingMapButton(QToolButton* button, const QString &mapName) {
|
||||
if (this->project) button->setDisabled(!this->project->mapNames.contains(mapName));
|
||||
}
|
||||
|
||||
void Editor::updateDivingMapsVisibility() {
|
||||
|
|
@ -1061,6 +1108,13 @@ void Editor::scaleMapView(int s) {
|
|||
ui->graphicsView_Connections->setTransform(transform);
|
||||
}
|
||||
|
||||
void Editor::setPlayerViewRect(const QRectF &rect) {
|
||||
delete this->playerViewRect;
|
||||
this->playerViewRect = new MovableRect(&this->settings->playerViewRectEnabled, rect, qRgb(255, 255, 255));
|
||||
if (ui->graphicsView_Map->scene())
|
||||
ui->graphicsView_Map->scene()->update();
|
||||
}
|
||||
|
||||
void Editor::updateCursorRectPos(int x, int y) {
|
||||
if (this->playerViewRect)
|
||||
this->playerViewRect->updateLocation(x, y);
|
||||
|
|
@ -1562,14 +1616,8 @@ void Editor::displayMapMetatiles() {
|
|||
map_item->draw(true);
|
||||
scene->addItem(map_item);
|
||||
|
||||
int tw = 16;
|
||||
int th = 16;
|
||||
scene->setSceneRect(
|
||||
-BORDER_DISTANCE * tw,
|
||||
-BORDER_DISTANCE * th,
|
||||
map_item->pixmap().width() + BORDER_DISTANCE * 2 * tw,
|
||||
map_item->pixmap().height() + BORDER_DISTANCE * 2 * th
|
||||
);
|
||||
// Scene rect is the map plus a margin that gives enough space to scroll and see the edge of the player view rectangle.
|
||||
scene->setSceneRect(this->layout->getVisibleRect() + QMargins(3,3,3,3));
|
||||
}
|
||||
|
||||
void Editor::clearMapMovementPermissions() {
|
||||
|
|
@ -1727,8 +1775,6 @@ void Editor::clearMapConnections() {
|
|||
}
|
||||
connection_items.clear();
|
||||
|
||||
const QSignalBlocker blocker1(ui->comboBox_DiveMap);
|
||||
const QSignalBlocker blocker2(ui->comboBox_EmergeMap);
|
||||
ui->comboBox_DiveMap->setCurrentText("");
|
||||
ui->comboBox_EmergeMap->setCurrentText("");
|
||||
|
||||
|
|
@ -1765,18 +1811,13 @@ void Editor::clearConnectionMask() {
|
|||
}
|
||||
}
|
||||
|
||||
// Hides connected map tiles that cannot be seen from the current map (beyond BORDER_DISTANCE).
|
||||
// Hides connected map tiles that cannot be seen from the current map
|
||||
void Editor::maskNonVisibleConnectionTiles() {
|
||||
clearConnectionMask();
|
||||
|
||||
QPainterPath mask;
|
||||
mask.addRect(scene->itemsBoundingRect().toRect());
|
||||
mask.addRect(
|
||||
-BORDER_DISTANCE * 16,
|
||||
-BORDER_DISTANCE * 16,
|
||||
(layout->getWidth() + BORDER_DISTANCE * 2) * 16,
|
||||
(layout->getHeight() + BORDER_DISTANCE * 2) * 16
|
||||
);
|
||||
mask.addRect(layout->getVisibleRect());
|
||||
|
||||
// Mask the tiles with the current theme's background color.
|
||||
QPen pen(ui->graphicsView_Map->palette().color(QPalette::Active, QPalette::Base));
|
||||
|
|
@ -1799,13 +1840,10 @@ void Editor::clearMapBorder() {
|
|||
void Editor::displayMapBorder() {
|
||||
clearMapBorder();
|
||||
|
||||
int borderWidth = this->layout->getBorderWidth();
|
||||
int borderHeight = this->layout->getBorderHeight();
|
||||
int borderHorzDist = this->layout->getBorderDrawWidth();
|
||||
int borderVertDist = this->layout->getBorderDrawHeight();
|
||||
QPixmap pixmap = this->layout->renderBorder();
|
||||
for (int y = -borderVertDist; y < this->layout->getHeight() + borderVertDist; y += borderHeight)
|
||||
for (int x = -borderHorzDist; x < this->layout->getWidth() + borderHorzDist; x += borderWidth) {
|
||||
const QMargins borderMargins = layout->getBorderMargins();
|
||||
for (int y = -borderMargins.top(); y < this->layout->getHeight() + borderMargins.bottom(); y += this->layout->getBorderHeight())
|
||||
for (int x = -borderMargins.left(); x < this->layout->getWidth() + borderMargins.right(); x += this->layout->getBorderWidth()) {
|
||||
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
|
||||
item->setX(x * 16);
|
||||
item->setY(y * 16);
|
||||
|
|
@ -2345,8 +2383,8 @@ void Editor::setCollisionGraphics() {
|
|||
|
||||
// Users are not required to provide an image that gives an icon for every elevation/collision combination.
|
||||
// Instead they tell us how many are provided in their image by specifying the number of columns and rows.
|
||||
const int imgColumns = projectConfig.collisionSheetWidth;
|
||||
const int imgRows = projectConfig.collisionSheetHeight;
|
||||
const int imgColumns = projectConfig.collisionSheetSize.width();
|
||||
const int imgRows = projectConfig.collisionSheetSize.height();
|
||||
|
||||
// Create a pixmap for the selector on the Collision tab. If a project was previously opened we'll also need to refresh the selector.
|
||||
this->collisionSheetPixmap = QPixmap::fromImage(imgSheet).scaled(MovementPermissionsSelector::CellWidth * imgColumns,
|
||||
|
|
|
|||
|
|
@ -261,6 +261,10 @@ void MainWindow::initCustomUI() {
|
|||
// Create map header data widget
|
||||
this->mapHeaderForm = new MapHeaderForm();
|
||||
ui->layout_HeaderData->addWidget(this->mapHeaderForm);
|
||||
|
||||
// Center zooming on the mouse
|
||||
ui->graphicsView_Map->setTransformationAnchor(QGraphicsView::ViewportAnchor::AnchorUnderMouse);
|
||||
ui->graphicsView_Map->setResizeAnchor(QGraphicsView::ViewportAnchor::AnchorUnderMouse);
|
||||
}
|
||||
|
||||
void MainWindow::initExtraSignals() {
|
||||
|
|
@ -348,6 +352,7 @@ void MainWindow::initEditor() {
|
|||
connect(this->editor, &Editor::tilesetUpdated, this, &Scripting::cb_TilesetUpdated);
|
||||
connect(ui->newEventToolButton, &NewEventToolButton::newEventAdded, this->editor, &Editor::addNewEvent);
|
||||
connect(ui->toolButton_deleteEvent, &QAbstractButton::clicked, this->editor, &Editor::deleteSelectedEvents);
|
||||
connect(ui->graphicsView_Connections, &ConnectionsView::pressedDelete, this->editor, &Editor::removeSelectedConnection);
|
||||
|
||||
this->loadUserSettings();
|
||||
|
||||
|
|
@ -583,6 +588,8 @@ void MainWindow::loadUserSettings() {
|
|||
ui->checkBox_ToggleBorder->setChecked(porymapConfig.showBorder);
|
||||
ui->actionShow_Events_In_Map_View->setChecked(porymapConfig.eventOverlayEnabled);
|
||||
|
||||
this->editor->gridSettings = porymapConfig.gridSettings;
|
||||
|
||||
setTheme(porymapConfig.theme);
|
||||
setDivingMapsVisible(porymapConfig.showDiveEmergeMaps);
|
||||
}
|
||||
|
|
@ -1202,6 +1209,8 @@ bool MainWindow::setProjectUI() {
|
|||
ui->newEventToolButton->setEventTypeVisible(Event::Type::SecretBase, projectConfig.eventSecretBaseEnabled);
|
||||
ui->newEventToolButton->setEventTypeVisible(Event::Type::CloneObject, projectConfig.eventCloneObjectEnabled);
|
||||
|
||||
this->editor->setPlayerViewRect(QRectF(0, 0, 16, 16).marginsAdded(projectConfig.playerViewDistance));
|
||||
|
||||
editor->setCollisionGraphics();
|
||||
ui->spinBox_SelectedElevation->setMaximum(Block::getMaxElevation());
|
||||
ui->spinBox_SelectedCollision->setMaximum(Block::getMaxCollision());
|
||||
|
|
@ -1244,10 +1253,7 @@ void MainWindow::clearProjectUI() {
|
|||
const QSignalBlocker b_SecondaryTileset(ui->comboBox_SecondaryTileset);
|
||||
ui->comboBox_SecondaryTileset->clear();
|
||||
|
||||
const QSignalBlocker b_DiveMap(ui->comboBox_DiveMap);
|
||||
ui->comboBox_DiveMap->clear();
|
||||
|
||||
const QSignalBlocker b_EmergeMap(ui->comboBox_EmergeMap);
|
||||
ui->comboBox_EmergeMap->clear();
|
||||
|
||||
const QSignalBlocker b_LayoutSelector(ui->comboBox_LayoutSelector);
|
||||
|
|
@ -1408,8 +1414,6 @@ void MainWindow::onNewMapCreated(Map *newMap, const QString &groupName) {
|
|||
// (other combo boxes like for warp destinations are repopulated when the map changes).
|
||||
int mapIndex = this->editor->project->mapNames.indexOf(newMap->name());
|
||||
if (mapIndex >= 0) {
|
||||
const QSignalBlocker b_DiveMap(ui->comboBox_DiveMap);
|
||||
const QSignalBlocker b_EmergeMap(ui->comboBox_EmergeMap);
|
||||
ui->comboBox_DiveMap->insertItem(mapIndex, newMap->name());
|
||||
ui->comboBox_EmergeMap->insertItem(mapIndex, newMap->name());
|
||||
}
|
||||
|
|
@ -1665,16 +1669,15 @@ void MainWindow::on_action_Save_triggered() {
|
|||
save(true);
|
||||
}
|
||||
|
||||
void MainWindow::save(bool currentOnly) {
|
||||
if (currentOnly) {
|
||||
this->editor->saveCurrent();
|
||||
} else {
|
||||
this->editor->saveAll();
|
||||
bool MainWindow::save(bool currentOnly) {
|
||||
bool success = currentOnly ? this->editor->saveCurrent() : this->editor->saveAll();
|
||||
if (!success) {
|
||||
RecentErrorMessage::show(QStringLiteral("Failed to save some project changes."), this);
|
||||
}
|
||||
updateWindowTitle();
|
||||
updateMapList();
|
||||
|
||||
if (!porymapConfig.shownInGameReloadMessage) {
|
||||
if (success && !porymapConfig.shownInGameReloadMessage) {
|
||||
// Show a one-time warning that the user may need to reload their map to see their new changes.
|
||||
InfoMessage::show(QStringLiteral("Reload your map in-game!\n\nIf your game is currently saved on a map you have edited, "
|
||||
"the changes may not appear until you leave the map and return."),
|
||||
|
|
@ -1683,6 +1686,7 @@ void MainWindow::save(bool currentOnly) {
|
|||
}
|
||||
|
||||
saveGlobalConfigs();
|
||||
return success;
|
||||
}
|
||||
|
||||
void MainWindow::duplicate() {
|
||||
|
|
@ -2018,6 +2022,7 @@ void MainWindow::on_actionGrid_Settings_triggered() {
|
|||
if (!this->gridSettingsDialog) {
|
||||
this->gridSettingsDialog = new GridSettingsDialog(&this->editor->gridSettings, this);
|
||||
connect(this->gridSettingsDialog, &GridSettingsDialog::changedGridSettings, this->editor, &Editor::updateMapGrid);
|
||||
connect(this->gridSettingsDialog, &GridSettingsDialog::accepted, [this] { porymapConfig.gridSettings = this->editor->gridSettings; });
|
||||
}
|
||||
openSubWindow(this->gridSettingsDialog);
|
||||
}
|
||||
|
|
@ -2620,7 +2625,8 @@ void MainWindow::on_pushButton_AddConnection_clicked() {
|
|||
return;
|
||||
|
||||
auto dialog = new NewMapConnectionDialog(this, this->editor->map, this->editor->project->mapNames);
|
||||
connect(dialog, &NewMapConnectionDialog::accepted, this->editor, &Editor::addConnection);
|
||||
connect(dialog, &NewMapConnectionDialog::newConnectionedAdded, this->editor, &Editor::addNewConnection);
|
||||
connect(dialog, &NewMapConnectionDialog::connectionReplaced, this->editor, &Editor::replaceConnection);
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
|
|
@ -2673,17 +2679,6 @@ void MainWindow::on_button_OpenEmergeMap_clicked() {
|
|||
userSetMap(ui->comboBox_EmergeMap->currentText());
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_DiveMap_currentTextChanged(const QString &mapName) {
|
||||
// Include empty names as an update (user is deleting the connection)
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName))
|
||||
editor->updateDiveMap(mapName);
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_EmergeMap_currentTextChanged(const QString &mapName) {
|
||||
if (mapName.isEmpty() || editor->project->mapNames.contains(mapName))
|
||||
editor->updateEmergeMap(mapName);
|
||||
}
|
||||
|
||||
void MainWindow::on_comboBox_PrimaryTileset_currentTextChanged(const QString &tilesetLabel)
|
||||
{
|
||||
if (editor->project->primaryTilesetLabels.contains(tilesetLabel) && editor->layout) {
|
||||
|
|
@ -3079,7 +3074,8 @@ bool MainWindow::closeProject() {
|
|||
|
||||
auto reply = msgBox.exec();
|
||||
if (reply == QMessageBox::Yes) {
|
||||
save();
|
||||
if (!save())
|
||||
return false;
|
||||
} else if (reply == QMessageBox::No) {
|
||||
logWarn("Closing project with unsaved changes.");
|
||||
} else if (reply == QMessageBox::Cancel) {
|
||||
|
|
|
|||
427
src/project.cpp
427
src/project.cpp
|
|
@ -29,8 +29,6 @@ int Project::num_tiles_total = 1024;
|
|||
int Project::num_metatiles_primary = 512;
|
||||
int Project::num_pals_primary = 6;
|
||||
int Project::num_pals_total = 13;
|
||||
int Project::max_map_data_size = 10240; // 0x2800
|
||||
int Project::default_map_dimension = 20;
|
||||
|
||||
Project::Project(QObject *parent) :
|
||||
QObject(parent),
|
||||
|
|
@ -458,7 +456,7 @@ Layout *Project::loadLayout(QString layoutId) {
|
|||
}
|
||||
|
||||
if (!loadLayout(layout)) {
|
||||
logError(QString("Failed to load layout '%1'").arg(layoutId));
|
||||
// Error should already be logged.
|
||||
return nullptr;
|
||||
}
|
||||
return layout;
|
||||
|
|
@ -599,12 +597,12 @@ bool Project::readMapLayouts() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Project::saveMapLayouts() {
|
||||
bool Project::saveMapLayouts() {
|
||||
QString layoutsFilepath = root + "/" + projectConfig.getFilePath(ProjectFilePath::json_layouts);
|
||||
QFile layoutsFile(layoutsFilepath);
|
||||
if (!layoutsFile.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Error: Could not open %1 for writing").arg(layoutsFilepath));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(layoutsFilepath).arg(layoutsFile.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderedJson::object layoutsObj;
|
||||
|
|
@ -638,6 +636,7 @@ void Project::saveMapLayouts() {
|
|||
OrderedJsonDoc jsonDoc(&layoutJson);
|
||||
jsonDoc.dump(&layoutsFile);
|
||||
layoutsFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::ignoreWatchedFileTemporarily(QString filepath) {
|
||||
|
|
@ -663,12 +662,12 @@ void Project::recordFileChange(const QString &filepath) {
|
|||
emit fileChanged(filepath);
|
||||
}
|
||||
|
||||
void Project::saveMapGroups() {
|
||||
bool Project::saveMapGroups() {
|
||||
QString mapGroupsFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_map_groups));
|
||||
QFile mapGroupsFile(mapGroupsFilepath);
|
||||
if (!mapGroupsFile.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Error: Could not open %1 for writing").arg(mapGroupsFilepath));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(mapGroupsFilepath).arg(mapGroupsFile.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderedJson::object mapGroupsObj;
|
||||
|
|
@ -698,14 +697,15 @@ void Project::saveMapGroups() {
|
|||
OrderedJsonDoc jsonDoc(&mapGroupJson);
|
||||
jsonDoc.dump(&mapGroupsFile);
|
||||
mapGroupsFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::saveRegionMapSections() {
|
||||
bool Project::saveRegionMapSections() {
|
||||
const QString filepath = QString("%1/%2").arg(this->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
|
||||
QFile file(filepath);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Could not open '%1' for writing").arg(filepath));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(filepath).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderedJson::array mapSectionArray;
|
||||
|
|
@ -739,16 +739,17 @@ void Project::saveRegionMapSections() {
|
|||
OrderedJsonDoc jsonDoc(&json);
|
||||
jsonDoc.dump(&file);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::saveWildMonData() {
|
||||
if (!this->wildEncountersLoaded) return;
|
||||
bool Project::saveWildMonData() {
|
||||
if (!this->wildEncountersLoaded) return true;
|
||||
|
||||
QString wildEncountersJsonFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_wild_encounters));
|
||||
QFile wildEncountersFile(wildEncountersJsonFilepath);
|
||||
if (!wildEncountersFile.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Error: Could not open %1 for writing").arg(wildEncountersJsonFilepath));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(wildEncountersJsonFilepath).arg(wildEncountersFile.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderedJson::object wildEncountersObject;
|
||||
|
|
@ -834,6 +835,7 @@ void Project::saveWildMonData() {
|
|||
OrderedJsonDoc jsonDoc(&encounterJson);
|
||||
jsonDoc.dump(&wildEncountersFile);
|
||||
wildEncountersFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
// For a map with a constant of 'MAP_FOO', returns a unique 'HEAL_LOCATION_FOO'.
|
||||
|
|
@ -850,25 +852,19 @@ QString Project::getNewHealLocationName(const Map* map) const {
|
|||
return toUniqueIdentifier(projectConfig.getIdentifier(ProjectIdentifier::define_heal_locations_prefix) + idName);
|
||||
}
|
||||
|
||||
void Project::saveHealLocations() {
|
||||
bool Project::saveHealLocations() {
|
||||
const QString filepath = QString("%1/%2").arg(this->root).arg(projectConfig.getFilePath(ProjectFilePath::json_heal_locations));
|
||||
QFile file(filepath);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Could not open '%1' for writing").arg(filepath));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(filepath).arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the JSON data for output.
|
||||
QMap<QString, QList<OrderedJson::object>> idNameToJson;
|
||||
for (auto i = this->healLocations.constBegin(); i != this->healLocations.constEnd(); i++) {
|
||||
const QString mapConstant = i.key();
|
||||
for (const auto &event : i.value()) {
|
||||
// Heal location events don't need to track the "map" field, we're already tracking it either with
|
||||
// the keys in the healLocations map or by virtue of the event being added to a particular Map object.
|
||||
// The global JSON data needs this field, so we add it back here.
|
||||
auto eventJson = event->buildEventJson(this);
|
||||
eventJson["map"] = mapConstant;
|
||||
idNameToJson[event->getIdName()].append(eventJson);
|
||||
for (const auto &events : this->healLocations) {
|
||||
for (const auto &event : events) {
|
||||
idNameToJson[event->getIdName()].append(event->buildEventJson(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -883,8 +879,8 @@ void Project::saveHealLocations() {
|
|||
}
|
||||
}
|
||||
// Save any heal locations that weren't covered above (should be any new data).
|
||||
for (auto i = idNameToJson.constBegin(); i != idNameToJson.constEnd(); i++) {
|
||||
for (const auto &object : i.value()) {
|
||||
for (const auto &objects : idNameToJson) {
|
||||
for (const auto &object : objects) {
|
||||
eventJsonArr.push_back(object);
|
||||
}
|
||||
}
|
||||
|
|
@ -898,17 +894,21 @@ void Project::saveHealLocations() {
|
|||
OrderedJsonDoc jsonDoc(&json);
|
||||
jsonDoc.dump(&file);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::saveTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
saveTilesetMetatileLabels(primaryTileset, secondaryTileset);
|
||||
if (primaryTileset)
|
||||
primaryTileset->save();
|
||||
if (secondaryTileset)
|
||||
secondaryTileset->save();
|
||||
bool Project::saveTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
bool success = saveTilesetMetatileLabels(primaryTileset, secondaryTileset);
|
||||
if (primaryTileset && !primaryTileset->save())
|
||||
success = false;
|
||||
if (secondaryTileset && !secondaryTileset->save())
|
||||
success = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
void Project::updateTilesetMetatileLabels(Tileset *tileset) {
|
||||
if (!tileset) return;
|
||||
|
||||
// Erase old labels, then repopulate with new labels
|
||||
const QString prefix = tileset->getMetatileLabelPrefix();
|
||||
this->metatileLabelsMap[tileset->name].clear();
|
||||
|
|
@ -943,11 +943,11 @@ QString Project::buildMetatileLabelsText(const QMap<QString, uint16_t> defines)
|
|||
return output;
|
||||
}
|
||||
|
||||
void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
bool Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *secondaryTileset) {
|
||||
// Skip writing the file if there are no labels in both the new and old sets
|
||||
if (metatileLabelsMap[primaryTileset->name].size() == 0 && primaryTileset->metatileLabels.size() == 0
|
||||
&& metatileLabelsMap[secondaryTileset->name].size() == 0 && secondaryTileset->metatileLabels.size() == 0)
|
||||
return;
|
||||
if ((!primaryTileset || (metatileLabelsMap[primaryTileset->name].size() == 0 && primaryTileset->metatileLabels.size() == 0))
|
||||
&& (!secondaryTileset || (metatileLabelsMap[secondaryTileset->name].size() == 0 && secondaryTileset->metatileLabels.size() == 0)))
|
||||
return true;
|
||||
|
||||
updateTilesetMetatileLabels(primaryTileset);
|
||||
updateTilesetMetatileLabels(secondaryTileset);
|
||||
|
|
@ -974,42 +974,23 @@ void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *second
|
|||
|
||||
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_labels);
|
||||
ignoreWatchedFileTemporarily(root + "/" + filename);
|
||||
saveTextFile(root + "/" + filename, outputText);
|
||||
return saveTextFile(root + "/" + filename, outputText);
|
||||
}
|
||||
|
||||
bool Project::loadLayoutTilesets(Layout *layout) {
|
||||
layout->tileset_primary = getTileset(layout->tileset_primary_label);
|
||||
if (!layout->tileset_primary) {
|
||||
QString defaultTileset = this->getDefaultPrimaryTilesetLabel();
|
||||
layout->tileset_primary_label = defaultTileset;
|
||||
layout->tileset_primary = getTileset(layout->tileset_primary_label);
|
||||
if (!layout->tileset_primary) {
|
||||
logError(QString("%1 has invalid primary tileset '%2'.").arg(layout->name).arg(layout->tileset_primary_label));
|
||||
return false;
|
||||
}
|
||||
logWarn(QString("%1 has invalid primary tileset '%2'. Using default '%3'").arg(layout->name).arg(layout->tileset_primary_label).arg(defaultTileset));
|
||||
}
|
||||
|
||||
layout->tileset_secondary = getTileset(layout->tileset_secondary_label);
|
||||
if (!layout->tileset_secondary) {
|
||||
QString defaultTileset = this->getDefaultSecondaryTilesetLabel();
|
||||
layout->tileset_secondary_label = defaultTileset;
|
||||
layout->tileset_secondary = getTileset(layout->tileset_secondary_label);
|
||||
if (!layout->tileset_secondary) {
|
||||
logError(QString("%1 has invalid secondary tileset '%2'.").arg(layout->name).arg(layout->tileset_secondary_label));
|
||||
return false;
|
||||
}
|
||||
logWarn(QString("%1 has invalid secondary tileset '%2'. Using default '%3'").arg(layout->name).arg(layout->tileset_secondary_label).arg(defaultTileset));
|
||||
}
|
||||
return true;
|
||||
return layout->tileset_primary && layout->tileset_secondary;
|
||||
}
|
||||
|
||||
Tileset* Project::loadTileset(QString label, Tileset *tileset) {
|
||||
auto memberMap = Tileset::getHeaderMemberMap(this->usingAsmTilesets);
|
||||
if (this->usingAsmTilesets) {
|
||||
// Read asm tileset header. Backwards compatibility
|
||||
const QStringList values = parser.getLabelValues(parser.parseAsm(projectConfig.getFilePath(ProjectFilePath::tilesets_headers_asm)), label);
|
||||
const QString path = projectConfig.getFilePath(ProjectFilePath::tilesets_headers_asm);
|
||||
const QStringList values = parser.getLabelValues(parser.parseAsm(path), label);
|
||||
if (values.isEmpty()) {
|
||||
logError(QString("Failed to find header data in '%1' for tileset '%2'.").arg(path).arg(label));
|
||||
return nullptr;
|
||||
}
|
||||
if (tileset == nullptr) {
|
||||
|
|
@ -1023,8 +1004,10 @@ Tileset* Project::loadTileset(QString label, Tileset *tileset) {
|
|||
tileset->metatile_attrs_label = values.value(memberMap.key("metatileAttributes"));
|
||||
} else {
|
||||
// Read C tileset header
|
||||
auto structs = parser.readCStructs(projectConfig.getFilePath(ProjectFilePath::tilesets_headers), label, memberMap);
|
||||
const QString path = projectConfig.getFilePath(ProjectFilePath::tilesets_headers);
|
||||
auto structs = parser.readCStructs(path, label, memberMap);
|
||||
if (!structs.contains(label)) {
|
||||
logError(QString("Failed to find header data in '%1' for tileset '%2'.").arg(path).arg(label));
|
||||
return nullptr;
|
||||
}
|
||||
if (tileset == nullptr) {
|
||||
|
|
@ -1039,7 +1022,11 @@ Tileset* Project::loadTileset(QString label, Tileset *tileset) {
|
|||
tileset->metatile_attrs_label = tilesetAttributes.value("metatileAttributes");
|
||||
}
|
||||
|
||||
loadTilesetAssets(tileset);
|
||||
if (!loadTilesetAssets(tileset)) {
|
||||
// Error should already be logged.
|
||||
delete tileset;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
tilesetCache.insert(label, tileset);
|
||||
return tileset;
|
||||
|
|
@ -1128,38 +1115,22 @@ void Project::setNewLayoutBorder(Layout *layout) {
|
|||
layout->lastCommitBlocks.borderDimensions = QSize(width, height);
|
||||
}
|
||||
|
||||
void Project::saveLayoutBorder(Layout *layout) {
|
||||
QString path = QString("%1/%2").arg(root).arg(layout->border_path);
|
||||
writeBlockdata(path, layout->border);
|
||||
}
|
||||
|
||||
void Project::saveLayoutBlockdata(Layout *layout) {
|
||||
QString path = QString("%1/%2").arg(root).arg(layout->blockdata_path);
|
||||
writeBlockdata(path, layout->blockdata);
|
||||
}
|
||||
|
||||
void Project::writeBlockdata(QString path, const Blockdata &blockdata) {
|
||||
QFile file(path);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
QByteArray data = blockdata.serialize();
|
||||
file.write(data);
|
||||
} else {
|
||||
logError(QString("Failed to open blockdata file for writing: '%1'").arg(path));
|
||||
}
|
||||
}
|
||||
|
||||
void Project::saveAll() {
|
||||
bool Project::saveAll() {
|
||||
bool success = true;
|
||||
for (auto map : this->maps) {
|
||||
saveMap(map, true); // Avoid double-saving the layouts
|
||||
if (!saveMap(map, true)) // Avoid double-saving the layouts
|
||||
success = false;
|
||||
}
|
||||
for (auto layout : this->mapLayouts) {
|
||||
saveLayout(layout);
|
||||
if (!saveLayout(layout))
|
||||
success = false;
|
||||
}
|
||||
saveGlobalData();
|
||||
if (!saveGlobalData()) success = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
void Project::saveMap(Map *map, bool skipLayout) {
|
||||
if (!map || !isMapLoaded(map)) return;
|
||||
bool Project::saveMap(Map *map, bool skipLayout) {
|
||||
if (!map || !isMapLoaded(map)) return true;
|
||||
|
||||
// Create/Modify a few collateral files for brand new maps.
|
||||
const QString folderPath = projectConfig.getFilePath(ProjectFilePath::data_map_folders) + map->name();
|
||||
|
|
@ -1167,7 +1138,7 @@ void Project::saveMap(Map *map, bool skipLayout) {
|
|||
if (!map->isPersistedToFile()) {
|
||||
if (!QDir::root().mkpath(fullPath)) {
|
||||
logError(QString("Failed to create directory for new map: '%1'").arg(fullPath));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create file data/maps/<map_name>/scripts.inc
|
||||
|
|
@ -1191,8 +1162,8 @@ void Project::saveMap(Map *map, bool skipLayout) {
|
|||
QString mapFilepath = fullPath + "/map.json";
|
||||
QFile mapFile(mapFilepath);
|
||||
if (!mapFile.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Error: Could not open %1 for writing").arg(mapFilepath));
|
||||
return;
|
||||
logError(QString("Could not open '%1' for writing: %2").arg(mapFilepath).arg(mapFile.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderedJson::object mapObj;
|
||||
|
|
@ -1288,72 +1259,61 @@ void Project::saveMap(Map *map, bool skipLayout) {
|
|||
jsonDoc.dump(&mapFile);
|
||||
mapFile.close();
|
||||
|
||||
if (!skipLayout) saveLayout(map->layout());
|
||||
|
||||
// Try to record the MAPSEC name in case this is a new name.
|
||||
addNewMapsec(map->header()->location());
|
||||
|
||||
map->setClean();
|
||||
|
||||
if (!skipLayout && !saveLayout(map->layout()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::saveLayout(Layout *layout) {
|
||||
bool Project::saveLayout(Layout *layout) {
|
||||
if (!layout || !isLayoutLoaded(layout))
|
||||
return;
|
||||
return true;
|
||||
|
||||
if (!layout->newFolderPath.isEmpty()) {
|
||||
// Layout directory doesn't exist yet, create it now.
|
||||
const QString fullPath = QString("%1/%2").arg(this->root).arg(layout->newFolderPath);
|
||||
if (!QDir::root().mkpath(fullPath)) {
|
||||
logError(QString("Failed to create directory for new layout: '%1'").arg(fullPath));
|
||||
return;
|
||||
}
|
||||
layout->newFolderPath = QString();
|
||||
}
|
||||
|
||||
saveLayoutBorder(layout);
|
||||
saveLayoutBlockdata(layout);
|
||||
if (!layout->save(this->root))
|
||||
return false;
|
||||
|
||||
// Update global data structures with current map data.
|
||||
updateLayout(layout);
|
||||
|
||||
layout->setClean();
|
||||
}
|
||||
|
||||
void Project::updateLayout(Layout *layout) {
|
||||
if (!this->layoutIdsMaster.contains(layout->id)) {
|
||||
this->layoutIdsMaster.append(layout->id);
|
||||
}
|
||||
|
||||
if (this->mapLayoutsMaster.contains(layout->id)) {
|
||||
this->mapLayoutsMaster[layout->id]->copyFrom(layout);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this->mapLayoutsMaster.insert(layout->id, layout->copy());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::saveGlobalData() {
|
||||
saveMapLayouts();
|
||||
saveMapGroups();
|
||||
saveRegionMapSections();
|
||||
saveHealLocations();
|
||||
saveWildMonData();
|
||||
saveConfig();
|
||||
bool Project::saveGlobalData() {
|
||||
bool success = true;
|
||||
if (!saveMapLayouts()) success = false;
|
||||
if (!saveMapGroups()) success = false;
|
||||
if (!saveRegionMapSections()) success = false;
|
||||
if (!saveHealLocations()) success = false;
|
||||
if (!saveWildMonData()) success = false;
|
||||
if (!saveConfig()) success = false;
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
this->hasUnsavedDataChanges = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::saveConfig() {
|
||||
projectConfig.save();
|
||||
userConfig.save();
|
||||
bool Project::saveConfig() {
|
||||
bool success = true;
|
||||
if (!projectConfig.save()) success = false;
|
||||
if (!userConfig.save()) success = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
void Project::loadTilesetAssets(Tileset* tileset) {
|
||||
if (tileset->name.isNull()) {
|
||||
return;
|
||||
}
|
||||
bool Project::loadTilesetAssets(Tileset* tileset) {
|
||||
readTilesetPaths(tileset);
|
||||
loadTilesetMetatileLabels(tileset);
|
||||
tileset->load();
|
||||
return tileset->load();
|
||||
}
|
||||
|
||||
void Project::readTilesetPaths(Tileset* tileset) {
|
||||
|
|
@ -1547,6 +1507,8 @@ bool Project::readTilesetMetatileLabels() {
|
|||
}
|
||||
|
||||
void Project::loadTilesetMetatileLabels(Tileset* tileset) {
|
||||
if (!tileset || tileset->name.isEmpty()) return;
|
||||
|
||||
QString metatileLabelPrefix = tileset->getMetatileLabelPrefix();
|
||||
|
||||
// Reverse map for faster lookup by metatile id
|
||||
|
|
@ -1588,29 +1550,24 @@ Tileset* Project::getTileset(QString label, bool forceLoad) {
|
|||
}
|
||||
}
|
||||
|
||||
void Project::saveTextFile(QString path, QString text) {
|
||||
bool Project::saveTextFile(const QString &path, const QString &text) {
|
||||
QFile file(path);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(text.toUtf8());
|
||||
} else {
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Could not open '%1' for writing: ").arg(path) + file.errorString());
|
||||
return false;
|
||||
}
|
||||
file.write(text.toUtf8());
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::appendTextFile(QString path, QString text) {
|
||||
bool Project::appendTextFile(const QString &path, const QString &text) {
|
||||
QFile file(path);
|
||||
if (file.open(QIODevice::Append)) {
|
||||
file.write(text.toUtf8());
|
||||
} else {
|
||||
if (!file.open(QIODevice::Append)) {
|
||||
logError(QString("Could not open '%1' for appending: ").arg(path) + file.errorString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Project::deleteFile(QString path) {
|
||||
QFile file(path);
|
||||
if (file.exists() && !file.remove()) {
|
||||
logError(QString("Could not delete file '%1': ").arg(path) + file.errorString());
|
||||
}
|
||||
file.write(text.toUtf8());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Project::readWildMonData() {
|
||||
|
|
@ -1700,19 +1657,22 @@ bool Project::readWildMonData() {
|
|||
// Each element describes a type of wild encounter Porymap can expect to find, and we represent this data with an EncounterField.
|
||||
// They should contain a name ("type"), the number of encounter slots and the ratio at which they occur ("encounter_rates"),
|
||||
// and whether the encounters are divided into groups (like fishing rods).
|
||||
for (const OrderedJson &fieldJson : mainArrayObject.take("fields").array_items()) {
|
||||
OrderedJson::array fieldsArray = mainArrayObject.take("fields").array_items();
|
||||
for (const OrderedJson &fieldJson : fieldsArray) {
|
||||
OrderedJson::object fieldObject = fieldJson.object_items();
|
||||
|
||||
EncounterField encounterField;
|
||||
encounterField.name = fieldObject.take("type").string_value();
|
||||
|
||||
for (auto val : fieldObject.take("encounter_rates").array_items()) {
|
||||
OrderedJson::array encounterRatesArray = fieldObject.take("encounter_rates").array_items();
|
||||
for (const auto &val : encounterRatesArray) {
|
||||
encounterField.encounterRates.append(val.int_value());
|
||||
}
|
||||
|
||||
// Each element of the "groups" array is an object with the group name as the key (e.g. "old_rod")
|
||||
// and an array of slot numbers indicating which encounter slots in this encounter type belong to that group.
|
||||
for (auto groupPair : fieldObject.take("groups").object_items()) {
|
||||
OrderedJson::object groups = fieldObject.take("groups").object_items();
|
||||
for (auto groupPair : groups) {
|
||||
const QString groupName = groupPair.first;
|
||||
for (auto slotNum : groupPair.second.array_items()) {
|
||||
encounterField.groups[groupName].append(slotNum.int_value());
|
||||
|
|
@ -1728,7 +1688,8 @@ bool Project::readWildMonData() {
|
|||
// Each element is an object that will tell us which map it's associated with,
|
||||
// its symbol name (which we will display in the Groups dropdown) and a list of
|
||||
// pokémon associated with any of the encounter types described by the data we parsed above.
|
||||
for (const auto &encounterJson : mainArrayObject.take("encounters").array_items()) {
|
||||
OrderedJson::array encountersArray = mainArrayObject.take("encounters").array_items();
|
||||
for (const auto &encounterJson : encountersArray) {
|
||||
OrderedJson::object encounterObj = encounterJson.object_items();
|
||||
|
||||
WildPokemonHeader header;
|
||||
|
|
@ -1750,7 +1711,8 @@ bool Project::readWildMonData() {
|
|||
encounterRateFrequencyMaps[field][monInfo.encounterRate]++;
|
||||
|
||||
// Read wild pokémon list
|
||||
for (const auto &monJson : encounterFieldObj.take("mons").array_items()) {
|
||||
OrderedJson::array monsArray = encounterFieldObj.take("mons").array_items();
|
||||
for (const auto &monJson : monsArray) {
|
||||
OrderedJson::object monObj = monJson.object_items();
|
||||
|
||||
WildPokemon newMon;
|
||||
|
|
@ -2036,8 +1998,8 @@ void Project::initNewMapSettings() {
|
|||
this->newMapSettings.layout.folderName = this->newMapSettings.name;
|
||||
this->newMapSettings.layout.name = QString();
|
||||
this->newMapSettings.layout.id = Layout::layoutConstantFromName(this->newMapSettings.name);
|
||||
this->newMapSettings.layout.width = getDefaultMapDimension();
|
||||
this->newMapSettings.layout.height = getDefaultMapDimension();
|
||||
this->newMapSettings.layout.width = this->defaultMapSize.width();
|
||||
this->newMapSettings.layout.height = this->defaultMapSize.height();
|
||||
this->newMapSettings.layout.borderWidth = DEFAULT_BORDER_WIDTH;
|
||||
this->newMapSettings.layout.borderHeight = DEFAULT_BORDER_HEIGHT;
|
||||
this->newMapSettings.layout.primaryTilesetLabel = getDefaultPrimaryTilesetLabel();
|
||||
|
|
@ -2059,8 +2021,8 @@ void Project::initNewMapSettings() {
|
|||
void Project::initNewLayoutSettings() {
|
||||
this->newLayoutSettings.name = QString();
|
||||
this->newLayoutSettings.id = Layout::layoutConstantFromName(this->newLayoutSettings.name);
|
||||
this->newLayoutSettings.width = getDefaultMapDimension();
|
||||
this->newLayoutSettings.height = getDefaultMapDimension();
|
||||
this->newLayoutSettings.width = this->defaultMapSize.width();
|
||||
this->newLayoutSettings.height = this->defaultMapSize.height();
|
||||
this->newLayoutSettings.borderWidth = DEFAULT_BORDER_WIDTH;
|
||||
this->newLayoutSettings.borderHeight = DEFAULT_BORDER_HEIGHT;
|
||||
this->newLayoutSettings.primaryTilesetLabel = getDefaultPrimaryTilesetLabel();
|
||||
|
|
@ -2153,7 +2115,12 @@ bool Project::readFieldmapProperties() {
|
|||
const QString numPalsTotalName = projectConfig.getIdentifier(ProjectIdentifier::define_pals_total);
|
||||
const QString maxMapSizeName = projectConfig.getIdentifier(ProjectIdentifier::define_map_size);
|
||||
const QString numTilesPerMetatileName = projectConfig.getIdentifier(ProjectIdentifier::define_tiles_per_metatile);
|
||||
const QSet<QString> names = {
|
||||
const QString mapOffsetWidthName = projectConfig.getIdentifier(ProjectIdentifier::define_map_offset_width);
|
||||
const QString mapOffsetHeightName = projectConfig.getIdentifier(ProjectIdentifier::define_map_offset_height);
|
||||
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
const QMap<QString, int> defines = parser.readCDefinesByName(filename, {
|
||||
numTilesPrimaryName,
|
||||
numTilesTotalName,
|
||||
numMetatilesPrimaryName,
|
||||
|
|
@ -2161,24 +2128,23 @@ bool Project::readFieldmapProperties() {
|
|||
numPalsTotalName,
|
||||
maxMapSizeName,
|
||||
numTilesPerMetatileName,
|
||||
};
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
const QMap<QString, int> defines = parser.readCDefinesByName(filename, names);
|
||||
mapOffsetWidthName,
|
||||
mapOffsetHeightName,
|
||||
});
|
||||
|
||||
auto loadDefine = [defines](const QString name, int * dest, int min, int max) {
|
||||
auto it = defines.find(name);
|
||||
if (it != defines.end()) {
|
||||
*dest = it.value();
|
||||
if (*dest < min) {
|
||||
logWarn(QString("Value for tileset property '%1' (%2) is below the minimum (%3). Defaulting to minimum.").arg(name).arg(*dest).arg(min));
|
||||
logWarn(QString("Value for '%1' (%2) is below the minimum (%3). Defaulting to minimum.").arg(name).arg(*dest).arg(min));
|
||||
*dest = min;
|
||||
} else if (*dest > max) {
|
||||
logWarn(QString("Value for tileset property '%1' (%2) is above the maximum (%3). Defaulting to maximum.").arg(name).arg(*dest).arg(max));
|
||||
logWarn(QString("Value for '%1' (%2) is above the maximum (%3). Defaulting to maximum.").arg(name).arg(*dest).arg(max));
|
||||
*dest = max;
|
||||
}
|
||||
} else {
|
||||
logWarn(QString("Value for tileset property '%1' not found. Using default (%2) instead.").arg(name).arg(*dest));
|
||||
logWarn(QString("Value for '%1' not found. Using default (%2) instead.").arg(name).arg(*dest));
|
||||
}
|
||||
};
|
||||
loadDefine(numPalsTotalName, &Project::num_pals_total, 2, INT_MAX); // In reality the max would be 16, but as far as Porymap is concerned it doesn't matter.
|
||||
|
|
@ -2190,25 +2156,42 @@ bool Project::readFieldmapProperties() {
|
|||
// we don't actually know what the maximum number of metatiles is.
|
||||
loadDefine(numMetatilesPrimaryName, &Project::num_metatiles_primary, 1, 0xFFFF - 1);
|
||||
|
||||
int w = 15, h = 14; // Default values of MAP_OFFSET_W, MAP_OFFSET_H
|
||||
loadDefine(mapOffsetWidthName, &w, 0, INT_MAX);
|
||||
loadDefine(mapOffsetHeightName, &h, 0, INT_MAX);
|
||||
this->mapSizeAddition = QSize(w, h);
|
||||
|
||||
this->maxMapDataSize = 10240; // Default value of MAX_MAP_DATA_SIZE
|
||||
this->defaultMapSize = projectConfig.defaultMapSize;
|
||||
auto it = defines.find(maxMapSizeName);
|
||||
if (it != defines.end()) {
|
||||
int min = getMapDataSize(1, 1);
|
||||
if (it.value() >= min) {
|
||||
Project::max_map_data_size = it.value();
|
||||
calculateDefaultMapSize();
|
||||
this->maxMapDataSize = it.value();
|
||||
if (getMapDataSize(this->defaultMapSize.width(), this->defaultMapSize.height()) > this->maxMapDataSize) {
|
||||
// The specified map size is too small to use the default map dimensions.
|
||||
// Calculate the largest square map size that we can use instead.
|
||||
int dimension = qFloor((qSqrt(4 * this->maxMapDataSize + 1) - (w + h)) / 2);
|
||||
logWarn(QString("Value for '%1' (%2) is too small to support the default %3x%4 map. Default changed to %5x%5.")
|
||||
.arg(maxMapSizeName)
|
||||
.arg(it.value())
|
||||
.arg(this->defaultMapSize.width())
|
||||
.arg(this->defaultMapSize.height())
|
||||
.arg(dimension));
|
||||
this->defaultMapSize = QSize(dimension, dimension);
|
||||
}
|
||||
} else {
|
||||
// must be large enough to support a 1x1 map
|
||||
logWarn(QString("Value for map property '%1' is %2, must be at least %3. Using default (%4) instead.")
|
||||
logWarn(QString("Value for '%1' (%2) is too small to support a 1x1 map. Must be at least %3. Using default (%4) instead.")
|
||||
.arg(maxMapSizeName)
|
||||
.arg(it.value())
|
||||
.arg(min)
|
||||
.arg(Project::max_map_data_size));
|
||||
.arg(this->maxMapDataSize));
|
||||
}
|
||||
}
|
||||
else {
|
||||
logWarn(QString("Value for map property '%1' not found. Using default (%2) instead.")
|
||||
logWarn(QString("Value for '%1' not found. Using default (%2) instead.")
|
||||
.arg(maxMapSizeName)
|
||||
.arg(Project::max_map_data_size));
|
||||
.arg(this->maxMapDataSize));
|
||||
}
|
||||
|
||||
it = defines.find(numTilesPerMetatileName);
|
||||
|
|
@ -3185,91 +3168,28 @@ QPixmap Project::getSpeciesIcon(const QString &species) {
|
|||
return pixmap;
|
||||
}
|
||||
|
||||
int Project::getNumTilesPrimary()
|
||||
{
|
||||
return Project::num_tiles_primary;
|
||||
int Project::getMapDataSize(int width, int height) const {
|
||||
return (width + this->mapSizeAddition.width())
|
||||
* (height + this->mapSizeAddition.height());
|
||||
}
|
||||
|
||||
int Project::getNumTilesTotal()
|
||||
{
|
||||
return Project::num_tiles_total;
|
||||
int Project::getMaxMapWidth() const {
|
||||
return (getMaxMapDataSize() / (1 + this->mapSizeAddition.height())) - this->mapSizeAddition.width();
|
||||
}
|
||||
|
||||
int Project::getNumMetatilesPrimary()
|
||||
{
|
||||
return Project::num_metatiles_primary;
|
||||
int Project::getMaxMapHeight() const {
|
||||
return (getMaxMapDataSize() / (1 + this->mapSizeAddition.width())) - this->mapSizeAddition.height();
|
||||
}
|
||||
|
||||
int Project::getNumMetatilesTotal()
|
||||
{
|
||||
return Block::getMaxMetatileId() + 1;
|
||||
}
|
||||
|
||||
int Project::getNumPalettesPrimary()
|
||||
{
|
||||
return Project::num_pals_primary;
|
||||
}
|
||||
|
||||
int Project::getNumPalettesTotal()
|
||||
{
|
||||
return Project::num_pals_total;
|
||||
}
|
||||
|
||||
int Project::getMaxMapDataSize()
|
||||
{
|
||||
return Project::max_map_data_size;
|
||||
}
|
||||
|
||||
int Project::getMapDataSize(int width, int height)
|
||||
{
|
||||
// + 15 and + 14 come from fieldmap.c in pokeruby/pokeemerald/pokefirered.
|
||||
return (width + 15) * (height + 14);
|
||||
}
|
||||
|
||||
int Project::getDefaultMapDimension()
|
||||
{
|
||||
return Project::default_map_dimension;
|
||||
}
|
||||
|
||||
int Project::getMaxMapWidth()
|
||||
{
|
||||
return (getMaxMapDataSize() / (1 + 14)) - 15;
|
||||
}
|
||||
|
||||
int Project::getMaxMapHeight()
|
||||
{
|
||||
return (getMaxMapDataSize() / (1 + 15)) - 14;
|
||||
}
|
||||
|
||||
bool Project::mapDimensionsValid(int width, int height) {
|
||||
bool Project::mapDimensionsValid(int width, int height) const {
|
||||
return getMapDataSize(width, height) <= getMaxMapDataSize();
|
||||
}
|
||||
|
||||
// Get largest possible square dimensions for a map up to maximum of 20x20 (arbitrary)
|
||||
bool Project::calculateDefaultMapSize(){
|
||||
int max = getMaxMapDataSize();
|
||||
|
||||
if (max >= getMapDataSize(20, 20)) {
|
||||
default_map_dimension = 20;
|
||||
} else if (max >= getMapDataSize(1, 1)) {
|
||||
// Below equation derived from max >= (x + 15) * (x + 14)
|
||||
// x^2 + 29x + (210 - max), then complete the square and simplify
|
||||
default_map_dimension = qFloor((qSqrt(4 * getMaxMapDataSize() + 1) - 29) / 2);
|
||||
} else {
|
||||
logError(QString("'%1' of %2 is too small to support a 1x1 map. Must be at least %3.")
|
||||
.arg(projectConfig.getIdentifier(ProjectIdentifier::define_map_size))
|
||||
.arg(max)
|
||||
.arg(getMapDataSize(1, 1)));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Object events have their own limit specified by ProjectIdentifier::define_obj_event_count.
|
||||
// The default value for this is 64. All events (object events included) are also limited by
|
||||
// the data types of the event counters in the project. This would normally be u8, so the limit is 255.
|
||||
// We let the users tell us this limit in case they change these data types.
|
||||
int Project::getMaxEvents(Event::Group group) {
|
||||
int Project::getMaxEvents(Event::Group group) const {
|
||||
if (group == Event::Group::Object)
|
||||
return qMin(this->maxObjectEvents, projectConfig.maxEventsPerGroup);
|
||||
return projectConfig.maxEventsPerGroup;
|
||||
|
|
@ -3291,6 +3211,17 @@ QString Project::getEmptySpeciesName() {
|
|||
return projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix) + projectConfig.getIdentifier(ProjectIdentifier::define_species_empty);
|
||||
}
|
||||
|
||||
// Get the distance in metatiles (rounded up) that the player is able to see in each direction in-game.
|
||||
// For the default view distance (i.e. assuming the player is centered in a 240x160 pixel GBA screen) this is 7x5 metatiles.
|
||||
QMargins Project::getMetatileViewDistance() {
|
||||
QMargins viewDistance = projectConfig.playerViewDistance;
|
||||
viewDistance.setTop(qCeil(viewDistance.top() / 16.0));
|
||||
viewDistance.setBottom(qCeil(viewDistance.bottom() / 16.0));
|
||||
viewDistance.setLeft(qCeil(viewDistance.left() / 16.0));
|
||||
viewDistance.setRight(qCeil(viewDistance.right() / 16.0));
|
||||
return viewDistance;
|
||||
}
|
||||
|
||||
// If the provided filepath is an absolute path to an existing file, return filepath.
|
||||
// If not, and the provided filepath is a relative path from the project dir to an existing file, return the relative path.
|
||||
// Otherwise return empty string.
|
||||
|
|
@ -3324,8 +3255,8 @@ void Project::applyParsedLimits() {
|
|||
projectConfig.defaultMetatileId = qMin(projectConfig.defaultMetatileId, Block::getMaxMetatileId());
|
||||
projectConfig.defaultElevation = qMin(projectConfig.defaultElevation, Block::getMaxElevation());
|
||||
projectConfig.defaultCollision = qMin(projectConfig.defaultCollision, Block::getMaxCollision());
|
||||
projectConfig.collisionSheetHeight = qMin(qMax(projectConfig.collisionSheetHeight, 1), Block::getMaxElevation() + 1);
|
||||
projectConfig.collisionSheetWidth = qMin(qMax(projectConfig.collisionSheetWidth, 1), Block::getMaxCollision() + 1);
|
||||
projectConfig.collisionSheetSize.setHeight(qMin(qMax(projectConfig.collisionSheetSize.height(), 1), Block::getMaxElevation() + 1));
|
||||
projectConfig.collisionSheetSize.setWidth(qMin(qMax(projectConfig.collisionSheetSize.width(), 1), Block::getMaxCollision() + 1));
|
||||
}
|
||||
|
||||
bool Project::hasUnsavedChanges() {
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ int MainWindow::getHeight() {
|
|||
void MainWindow::setDimensions(int width, int height) {
|
||||
if (!this->editor || !this->editor->layout)
|
||||
return;
|
||||
if (!Project::mapDimensionsValid(width, height))
|
||||
if (this->editor->project && !this->editor->project->mapDimensionsValid(width, height))
|
||||
return;
|
||||
this->editor->layout->setDimensions(width, height);
|
||||
this->tryCommitMapChanges(true);
|
||||
|
|
@ -237,7 +237,7 @@ void MainWindow::setDimensions(int width, int height) {
|
|||
void MainWindow::setWidth(int width) {
|
||||
if (!this->editor || !this->editor->layout)
|
||||
return;
|
||||
if (!Project::mapDimensionsValid(width, this->editor->layout->getHeight()))
|
||||
if (this->editor->project && !this->editor->project->mapDimensionsValid(width, this->editor->layout->getHeight()))
|
||||
return;
|
||||
this->editor->layout->setDimensions(width, this->editor->layout->getHeight());
|
||||
this->tryCommitMapChanges(true);
|
||||
|
|
@ -247,7 +247,7 @@ void MainWindow::setWidth(int width) {
|
|||
void MainWindow::setHeight(int height) {
|
||||
if (!this->editor || !this->editor->layout)
|
||||
return;
|
||||
if (!Project::mapDimensionsValid(this->editor->layout->getWidth(), height))
|
||||
if (this->editor->project && !this->editor->project->mapDimensionsValid(this->editor->layout->getWidth(), height))
|
||||
return;
|
||||
this->editor->layout->setDimensions(this->editor->layout->getWidth(), height);
|
||||
this->tryCommitMapChanges(true);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ ConnectionPixmapItem::ConnectionPixmapItem(MapConnection* connection)
|
|||
connection(connection)
|
||||
{
|
||||
this->setEditable(true);
|
||||
setFlag(ItemIsFocusable, true);
|
||||
this->basePixmap = pixmap();
|
||||
updateOrigin();
|
||||
render(false);
|
||||
|
|
@ -119,10 +118,6 @@ bool ConnectionPixmapItem::getEditable() {
|
|||
}
|
||||
|
||||
void ConnectionPixmapItem::setSelected(bool selected) {
|
||||
if (selected && !hasFocus()) {
|
||||
setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
|
||||
if (this->selected == selected)
|
||||
return;
|
||||
this->selected = selected;
|
||||
|
|
@ -132,7 +127,7 @@ void ConnectionPixmapItem::setSelected(bool selected) {
|
|||
}
|
||||
|
||||
void ConnectionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *) {
|
||||
setFocus(Qt::MouseFocusReason);
|
||||
this->setSelected(true);
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||
|
|
@ -143,18 +138,3 @@ void ConnectionPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
|||
void ConnectionPixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
|
||||
emit connectionItemDoubleClicked(this->connection);
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::keyPressEvent(QKeyEvent* event) {
|
||||
if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace) {
|
||||
emit deleteRequested(this->connection);
|
||||
} else {
|
||||
QGraphicsPixmapItem::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::focusInEvent(QFocusEvent* event) {
|
||||
if (!this->getEditable())
|
||||
return;
|
||||
this->setSelected(true);
|
||||
QGraphicsPixmapItem::focusInEvent(event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,44 +7,55 @@
|
|||
|
||||
ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connection, const QStringList &mapNames) :
|
||||
QFrame(parent),
|
||||
ui(new Ui::ConnectionsListItem)
|
||||
ui(new Ui::ConnectionsListItem),
|
||||
connection(connection),
|
||||
map(connection->parentMap())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
const QSignalBlocker blocker1(ui->comboBox_Direction);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Map);
|
||||
const QSignalBlocker blocker3(ui->spinBox_Offset);
|
||||
|
||||
ui->comboBox_Direction->setEditable(false);
|
||||
// Direction
|
||||
const QSignalBlocker b_Direction(ui->comboBox_Direction);
|
||||
ui->comboBox_Direction->setMinimumContentsLength(0);
|
||||
ui->comboBox_Direction->addItems(MapConnection::cardinalDirections);
|
||||
ui->comboBox_Direction->installEventFilter(this);
|
||||
|
||||
connect(ui->comboBox_Direction, &NoScrollComboBox::editingFinished, this, &ConnectionsListItem::commitDirection);
|
||||
|
||||
// Map
|
||||
const QSignalBlocker b_Map(ui->comboBox_Map);
|
||||
ui->comboBox_Map->setMinimumContentsLength(6);
|
||||
ui->comboBox_Map->addItems(mapNames);
|
||||
ui->comboBox_Map->setFocusedScrollingEnabled(false); // Scrolling could cause rapid changes to many different maps
|
||||
ui->comboBox_Map->setInsertPolicy(QComboBox::NoInsert);
|
||||
ui->comboBox_Map->installEventFilter(this);
|
||||
|
||||
ui->spinBox_Offset->setMinimum(INT_MIN);
|
||||
ui->spinBox_Offset->setMaximum(INT_MAX);
|
||||
connect(ui->comboBox_Map, &QComboBox::currentTextChanged, this, &ConnectionsListItem::commitMap);
|
||||
|
||||
// Invalid map names are not considered a change. If editing finishes with an invalid name, restore the previous name.
|
||||
connect(ui->comboBox_Map->lineEdit(), &QLineEdit::editingFinished, [this] {
|
||||
const QSignalBlocker blocker(ui->comboBox_Map);
|
||||
if (ui->comboBox_Map->findText(ui->comboBox_Map->currentText()) < 0)
|
||||
const QSignalBlocker b(ui->comboBox_Map);
|
||||
if (this->connection && ui->comboBox_Map->findText(ui->comboBox_Map->currentText()) < 0)
|
||||
ui->comboBox_Map->setTextItem(this->connection->targetMapName());
|
||||
});
|
||||
|
||||
// Distinguish between move actions for the edit history
|
||||
connect(ui->spinBox_Offset, &QSpinBox::editingFinished, [this] { this->actionId++; });
|
||||
// Offset
|
||||
const QSignalBlocker b_Offset(ui->spinBox_Offset);
|
||||
ui->spinBox_Offset->setMinimum(INT_MIN);
|
||||
ui->spinBox_Offset->setMaximum(INT_MAX);
|
||||
ui->spinBox_Offset->installEventFilter(this);
|
||||
|
||||
connect(ui->spinBox_Offset, &QSpinBox::editingFinished, [this] { this->actionId++; }); // Distinguish between move actions for the edit history
|
||||
connect(ui->spinBox_Offset, QOverload<int>::of(&QSpinBox::valueChanged), this, &ConnectionsListItem::commitMove);
|
||||
|
||||
// If the connection changes externally we want to update to reflect the change.
|
||||
connect(connection, &MapConnection::offsetChanged, this, &ConnectionsListItem::updateUI);
|
||||
connect(connection, &MapConnection::directionChanged, this, &ConnectionsListItem::updateUI);
|
||||
connect(connection, &MapConnection::targetMapNameChanged, this, &ConnectionsListItem::updateUI);
|
||||
|
||||
this->connection = connection;
|
||||
this->map = connection->parentMap();
|
||||
connect(ui->button_Delete, &QToolButton::clicked, this, &ConnectionsListItem::commitRemove);
|
||||
connect(ui->button_OpenMap, &QToolButton::clicked, [this] { emit openMapClicked(this->connection); });
|
||||
|
||||
this->updateUI();
|
||||
}
|
||||
|
||||
|
|
@ -66,13 +77,19 @@ void ConnectionsListItem::updateUI() {
|
|||
ui->spinBox_Offset->setValue(this->connection->offset());
|
||||
}
|
||||
|
||||
bool ConnectionsListItem::eventFilter(QObject*, QEvent *event) {
|
||||
if (event->type() == QEvent::FocusIn)
|
||||
this->setSelected(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConnectionsListItem::setSelected(bool selected) {
|
||||
if (selected == this->isSelected)
|
||||
return;
|
||||
this->isSelected = selected;
|
||||
|
||||
this->setStyleSheet(selected ? ".ConnectionsListItem { border: 1px solid rgb(255, 0, 255); }"
|
||||
: ".ConnectionsListItem { border-width: 1px; }");
|
||||
this->setStyleSheet(selected ? QStringLiteral(".ConnectionsListItem { border: 1px solid rgb(255, 0, 255); }")
|
||||
: QStringLiteral(".ConnectionsListItem { border-width: 1px; }"));
|
||||
if (selected)
|
||||
emit this->selected();
|
||||
}
|
||||
|
|
@ -81,42 +98,34 @@ void ConnectionsListItem::mousePressEvent(QMouseEvent *) {
|
|||
this->setSelected(true);
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_comboBox_Direction_currentTextChanged(QString direction) {
|
||||
this->setSelected(true);
|
||||
if (this->map)
|
||||
void ConnectionsListItem::commitDirection() {
|
||||
const QString direction = ui->comboBox_Direction->currentText();
|
||||
if (!this->connection || this->connection->direction() == direction)
|
||||
return;
|
||||
|
||||
if (MapConnection::isDiving(direction)) {
|
||||
// Diving maps are displayed separately, no support right now for replacing a list item with a diving map.
|
||||
// For now just restore the original direction.
|
||||
ui->comboBox_Direction->setCurrentText(this->connection->direction());
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->map) {
|
||||
this->map->commit(new MapConnectionChangeDirection(this->connection, direction));
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_comboBox_Map_currentTextChanged(QString mapName) {
|
||||
this->setSelected(true);
|
||||
void ConnectionsListItem::commitMap(const QString &mapName) {
|
||||
if (this->map && ui->comboBox_Map->findText(mapName) >= 0)
|
||||
this->map->commit(new MapConnectionChangeMap(this->connection, mapName));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_spinBox_Offset_valueChanged(int offset) {
|
||||
this->setSelected(true);
|
||||
void ConnectionsListItem::commitMove(int offset) {
|
||||
if (this->map)
|
||||
this->map->commit(new MapConnectionMove(this->connection, offset, this->actionId));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_button_Delete_clicked() {
|
||||
void ConnectionsListItem::commitRemove() {
|
||||
if (this->map)
|
||||
this->map->commit(new MapConnectionRemove(this->map, this->connection));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_button_OpenMap_clicked() {
|
||||
emit openMapClicked(this->connection);
|
||||
}
|
||||
|
||||
void ConnectionsListItem::focusInEvent(QFocusEvent* event) {
|
||||
this->setSelected(true);
|
||||
QFrame::focusInEvent(event);
|
||||
}
|
||||
|
||||
void ConnectionsListItem::keyPressEvent(QKeyEvent* event) {
|
||||
if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace) {
|
||||
on_button_Delete_clicked();
|
||||
} else {
|
||||
QFrame::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "customattributestable.h"
|
||||
#include "parseutil.h"
|
||||
#include "noscrollspinbox.h"
|
||||
#include "utility.h"
|
||||
#include <QHeaderView>
|
||||
#include <QScrollBar>
|
||||
|
||||
|
|
@ -96,7 +97,7 @@ int CustomAttributesTable::addAttribute(const QString &key, const QJsonValue &va
|
|||
keyItem->setFlags(Qt::ItemIsEnabled);
|
||||
keyItem->setData(DataRole::JsonType, type); // Record the type for writing to the file
|
||||
keyItem->setTextAlignment(Qt::AlignCenter);
|
||||
keyItem->setToolTip(key); // Display name as tool tip in case it's too long to see in the cell
|
||||
keyItem->setToolTip(Util::toHtmlParagraph(key)); // Display name as tool tip in case it's too long to see in the cell
|
||||
this->setItem(rowIndex, Column::Key, keyItem);
|
||||
|
||||
// Add value to table
|
||||
|
|
|
|||
|
|
@ -38,9 +38,5 @@ void DivingMapPixmapItem::onTargetMapChanged() {
|
|||
}
|
||||
|
||||
void DivingMapPixmapItem::setComboText(const QString &text) {
|
||||
if (!m_combo)
|
||||
return;
|
||||
|
||||
const QSignalBlocker blocker(m_combo);
|
||||
m_combo->setCurrentText(text);
|
||||
if (m_combo) m_combo->setCurrentText(text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,15 +239,16 @@ void ObjectFrame::setup() {
|
|||
// sprite combo
|
||||
QFormLayout *l_form_sprite = new QFormLayout();
|
||||
this->combo_sprite = new NoScrollComboBox(this);
|
||||
this->combo_sprite->setToolTip("The sprite graphics to use for this object.");
|
||||
static const QString combo_sprite_toolTip = Util::toHtmlParagraph("The sprite graphics to use for this object.");
|
||||
this->combo_sprite->setToolTip(combo_sprite_toolTip);
|
||||
l_form_sprite->addRow("Sprite", this->combo_sprite);
|
||||
this->layout_contents->addLayout(l_form_sprite);
|
||||
|
||||
// movement
|
||||
QFormLayout *l_form_movement = new QFormLayout();
|
||||
this->combo_movement = new NoScrollComboBox(this);
|
||||
this->combo_movement->setToolTip("The object's natural movement behavior when\n"
|
||||
"the player is not interacting with it.");
|
||||
static const QString combo_movement_toolTip = Util::toHtmlParagraph("The object's natural movement behavior when the player is not interacting with it.");
|
||||
this->combo_movement->setToolTip(combo_movement_toolTip);
|
||||
l_form_movement->addRow("Movement", this->combo_movement);
|
||||
this->layout_contents->addLayout(l_form_movement);
|
||||
|
||||
|
|
@ -256,15 +257,15 @@ void ObjectFrame::setup() {
|
|||
this->spinner_radius_x = new NoScrollSpinBox(this);
|
||||
this->spinner_radius_x->setMinimum(0);
|
||||
this->spinner_radius_x->setMaximum(255);
|
||||
this->spinner_radius_x->setToolTip("The maximum number of metatiles this object\n"
|
||||
"is allowed to move left or right during its\n"
|
||||
"normal movement behavior actions.");
|
||||
static const QString spinner_radius_x_toolTip = Util::toHtmlParagraph("The maximum number of metatiles this object is allowed to move left "
|
||||
"or right during its normal movement behavior actions.");
|
||||
this->spinner_radius_x->setToolTip(spinner_radius_x_toolTip);
|
||||
this->spinner_radius_y = new NoScrollSpinBox(this);
|
||||
this->spinner_radius_y->setMinimum(0);
|
||||
this->spinner_radius_y->setMaximum(255);
|
||||
this->spinner_radius_y->setToolTip("The maximum number of metatiles this object\n"
|
||||
"is allowed to move up or down during its\n"
|
||||
"normal movement behavior actions.");
|
||||
static const QString spinner_radius_y_toolTip = Util::toHtmlParagraph("The maximum number of metatiles this object is allowed to move up "
|
||||
"or down during its normal movement behavior actions.");
|
||||
this->spinner_radius_y->setToolTip(spinner_radius_y_toolTip);
|
||||
l_form_radii_xy->addRow("Movement Radius X", this->spinner_radius_x);
|
||||
l_form_radii_xy->addRow("Movement Radius Y", this->spinner_radius_y);
|
||||
this->layout_contents->addLayout(l_form_radii_xy);
|
||||
|
|
@ -272,11 +273,13 @@ void ObjectFrame::setup() {
|
|||
// script
|
||||
QFormLayout *l_form_script = new QFormLayout();
|
||||
this->combo_script = new NoScrollComboBox(this);
|
||||
this->combo_script->setToolTip("The script which is executed with this event.");
|
||||
static const QString combo_script_toolTip = Util::toHtmlParagraph("The script that is executed with this event.");
|
||||
this->combo_script->setToolTip(combo_script_toolTip);
|
||||
|
||||
// Add button next to combo which opens combo's current script.
|
||||
this->button_script = new QToolButton(this);
|
||||
this->button_script->setToolTip("Go to this script definition in text editor.");
|
||||
static const QString button_script_toolTip = Util::toHtmlParagraph("Go to this script definition in text editor.");
|
||||
this->button_script->setToolTip(button_script_toolTip);
|
||||
this->button_script->setFixedSize(this->combo_script->height(), this->combo_script->height());
|
||||
this->button_script->setIcon(QFileIconProvider().icon(QFileIconProvider::File));
|
||||
|
||||
|
|
@ -291,24 +294,25 @@ void ObjectFrame::setup() {
|
|||
// event flag
|
||||
QFormLayout *l_form_flag = new QFormLayout();
|
||||
this->combo_flag = new NoScrollComboBox(this);
|
||||
this->combo_flag->setToolTip("The flag which hides the object when set.");
|
||||
static const QString combo_flag_toolTip = Util::toHtmlParagraph("The flag that hides the object when set.");
|
||||
this->combo_flag->setToolTip(combo_flag_toolTip);
|
||||
l_form_flag->addRow("Event Flag", this->combo_flag);
|
||||
this->layout_contents->addLayout(l_form_flag);
|
||||
|
||||
// trainer type
|
||||
QFormLayout *l_form_trainer = new QFormLayout();
|
||||
this->combo_trainer_type = new NoScrollComboBox(this);
|
||||
this->combo_trainer_type->setToolTip("The trainer type of this object event.\n"
|
||||
"If it is not a trainer, use NONE. SEE ALL DIRECTIONS\n"
|
||||
"should only be used with a sight radius of 1.");
|
||||
static const QString combo_trainer_type_toolTip = Util::toHtmlParagraph("The trainer type of this object event. If it is not a trainer, use NONE. "
|
||||
"SEE ALL DIRECTIONS should only be used with a sight radius of 1.");
|
||||
this->combo_trainer_type->setToolTip(combo_trainer_type_toolTip);
|
||||
l_form_trainer->addRow("Trainer Type", this->combo_trainer_type);
|
||||
this->layout_contents->addLayout(l_form_trainer);
|
||||
|
||||
// sight radius / berry tree id
|
||||
QFormLayout *l_form_radius_treeid = new QFormLayout();
|
||||
this->combo_radius_treeid = new NoScrollComboBox(this);
|
||||
this->combo_radius_treeid->setToolTip("The maximum sight range of a trainer,\n"
|
||||
"OR the unique id of the berry tree.");
|
||||
static const QString combo_radius_treeid_toolTip = Util::toHtmlParagraph("The maximum sight range of a trainer, OR the unique id of the berry tree.");
|
||||
this->combo_radius_treeid->setToolTip(combo_radius_treeid_toolTip);
|
||||
l_form_radius_treeid->addRow("Sight Radius / Berry Tree ID", this->combo_radius_treeid);
|
||||
this->layout_contents->addLayout(l_form_radius_treeid);
|
||||
|
||||
|
|
@ -470,14 +474,16 @@ void CloneObjectFrame::setup() {
|
|||
// clone map id combo
|
||||
QFormLayout *l_form_dest_map = new QFormLayout();
|
||||
this->combo_target_map = new NoScrollComboBox(this);
|
||||
this->combo_target_map->setToolTip("The name of the map that the object being cloned is on.");
|
||||
static const QString combo_target_map_toolTip = Util::toHtmlParagraph("The name of the map that the object being cloned is on.");
|
||||
this->combo_target_map->setToolTip(combo_target_map_toolTip);
|
||||
l_form_dest_map->addRow("Target Map", this->combo_target_map);
|
||||
this->layout_contents->addLayout(l_form_dest_map);
|
||||
|
||||
// clone local id combo
|
||||
QFormLayout *l_form_dest_id = new QFormLayout();
|
||||
this->combo_target_id = new NoScrollComboBox(this);
|
||||
this->combo_target_id->setToolTip("The Local ID name or number of the object being cloned.");
|
||||
static const QString combo_target_id_toolTip = Util::toHtmlParagraph("The Local ID name or number of the object being cloned.");
|
||||
this->combo_target_id->setToolTip(combo_target_id_toolTip);
|
||||
l_form_dest_id->addRow("Target Local ID", this->combo_target_id);
|
||||
this->layout_contents->addLayout(l_form_dest_id);
|
||||
|
||||
|
|
@ -577,21 +583,21 @@ void WarpFrame::setup() {
|
|||
// desination map combo
|
||||
QFormLayout *l_form_dest_map = new QFormLayout();
|
||||
this->combo_dest_map = new NoScrollComboBox(this);
|
||||
this->combo_dest_map->setToolTip("The destination map name of the warp.");
|
||||
static const QString combo_dest_map_toolTip = Util::toHtmlParagraph("The destination map name of the warp.");
|
||||
this->combo_dest_map->setToolTip(combo_dest_map_toolTip);
|
||||
l_form_dest_map->addRow("Destination Map", this->combo_dest_map);
|
||||
this->layout_contents->addLayout(l_form_dest_map);
|
||||
|
||||
// desination warp id
|
||||
QFormLayout *l_form_dest_warp = new QFormLayout();
|
||||
this->combo_dest_warp = new NoScrollComboBox(this);
|
||||
this->combo_dest_warp->setToolTip("The warp id on the destination map.");
|
||||
static const QString combo_dest_warp_toolTip = Util::toHtmlParagraph("The warp id on the destination map.");
|
||||
this->combo_dest_warp->setToolTip(combo_dest_warp_toolTip);
|
||||
l_form_dest_warp->addRow("Destination Warp", this->combo_dest_warp);
|
||||
this->layout_contents->addLayout(l_form_dest_warp);
|
||||
|
||||
// warning
|
||||
static const QString warningText = "Warning:\n"
|
||||
"This warp event is not positioned on a metatile with a warp behavior.\n"
|
||||
"Click this warning for more details.";
|
||||
auto warningText = QStringLiteral("Warning:\nThis warp event is not positioned on a metatile with a warp behavior.\nClick this warning for more details.");
|
||||
QVBoxLayout *l_vbox_warning = new QVBoxLayout();
|
||||
this->warning = new QPushButton(warningText, this);
|
||||
this->warning->setFlat(true);
|
||||
|
|
@ -683,22 +689,25 @@ void TriggerFrame::setup() {
|
|||
// script combo
|
||||
QFormLayout *l_form_script = new QFormLayout();
|
||||
this->combo_script = new NoScrollComboBox(this);
|
||||
this->combo_script->setToolTip("The script which is executed with this event.");
|
||||
static const QString combo_script_toolTip = Util::toHtmlParagraph("The script that is executed with this event.");
|
||||
this->combo_script->setToolTip(combo_script_toolTip);
|
||||
l_form_script->addRow("Script", this->combo_script);
|
||||
this->layout_contents->addLayout(l_form_script);
|
||||
|
||||
// var combo
|
||||
QFormLayout *l_form_var = new QFormLayout();
|
||||
this->combo_var = new NoScrollComboBox(this);
|
||||
this->combo_var->setToolTip("The variable by which the script is triggered.\n"
|
||||
"The script is triggered when this variable's value matches 'Var Value'.");
|
||||
static const QString combo_var_toolTip = Util::toHtmlParagraph("The variable by which the script is triggered. "
|
||||
"The script is triggered when this variable's value matches 'Var Value'.");
|
||||
this->combo_var->setToolTip(combo_var_toolTip);
|
||||
l_form_var->addRow("Var", this->combo_var);
|
||||
this->layout_contents->addLayout(l_form_var);
|
||||
|
||||
// var value combo
|
||||
QFormLayout *l_form_var_val = new QFormLayout();
|
||||
this->combo_var_value = new NoScrollComboBox(this);
|
||||
this->combo_var_value->setToolTip("The variable's value which triggers the script.");
|
||||
static const QString combo_var_value_toolTip = Util::toHtmlParagraph("The variable's value that triggers the script.");
|
||||
this->combo_var_value->setToolTip(combo_var_value_toolTip);
|
||||
l_form_var_val->addRow("Var Value", this->combo_var_value);
|
||||
this->layout_contents->addLayout(l_form_var_val);
|
||||
|
||||
|
|
@ -767,7 +776,8 @@ void WeatherTriggerFrame::setup() {
|
|||
// weather combo
|
||||
QFormLayout *l_form_weather = new QFormLayout();
|
||||
this->combo_weather = new NoScrollComboBox(this);
|
||||
this->combo_weather->setToolTip("The weather that starts when the player steps on this spot.");
|
||||
static const QString combo_weather_toolTip = Util::toHtmlParagraph("The weather that starts when the player steps on this spot.");
|
||||
this->combo_weather->setToolTip(combo_weather_toolTip);
|
||||
l_form_weather->addRow("Weather", this->combo_weather);
|
||||
this->layout_contents->addLayout(l_form_weather);
|
||||
|
||||
|
|
@ -815,15 +825,16 @@ void SignFrame::setup() {
|
|||
// facing dir combo
|
||||
QFormLayout *l_form_facing_dir = new QFormLayout();
|
||||
this->combo_facing_dir = new NoScrollComboBox(this);
|
||||
this->combo_facing_dir->setToolTip("The direction which the player must be facing\n"
|
||||
"to be able to interact with this event.");
|
||||
static const QString combo_facing_dir_toolTip = Util::toHtmlParagraph("The direction that the player must be facing to be able to interact with this event.");
|
||||
this->combo_facing_dir->setToolTip(combo_facing_dir_toolTip);
|
||||
l_form_facing_dir->addRow("Player Facing Direction", this->combo_facing_dir);
|
||||
this->layout_contents->addLayout(l_form_facing_dir);
|
||||
|
||||
// script combo
|
||||
QFormLayout *l_form_script = new QFormLayout();
|
||||
this->combo_script = new NoScrollComboBox(this);
|
||||
this->combo_script->setToolTip("The script which is executed with this event.");
|
||||
static const QString combo_script_toolTip = Util::toHtmlParagraph("The script that is executed with this event.");
|
||||
this->combo_script->setToolTip(combo_script_toolTip);
|
||||
l_form_script->addRow("Script", this->combo_script);
|
||||
this->layout_contents->addLayout(l_form_script);
|
||||
|
||||
|
|
@ -882,14 +893,16 @@ void HiddenItemFrame::setup() {
|
|||
// item combo
|
||||
QFormLayout *l_form_item = new QFormLayout();
|
||||
this->combo_item = new NoScrollComboBox(this);
|
||||
this->combo_item->setToolTip("The item to be given.");
|
||||
static const QString combo_item_toolTip = Util::toHtmlParagraph("The item to be given.");
|
||||
this->combo_item->setToolTip(combo_item_toolTip);
|
||||
l_form_item->addRow("Item", this->combo_item);
|
||||
this->layout_contents->addLayout(l_form_item);
|
||||
|
||||
// flag combo
|
||||
QFormLayout *l_form_flag = new QFormLayout();
|
||||
this->combo_flag = new NoScrollComboBox(this);
|
||||
this->combo_flag->setToolTip("The flag which is set when the hidden item is picked up.");
|
||||
static const QString combo_flag_toolTip = Util::toHtmlParagraph("The flag that is set when the hidden item is picked up.");
|
||||
this->combo_flag->setToolTip(combo_flag_toolTip);
|
||||
l_form_flag->addRow("Flag", this->combo_flag);
|
||||
this->layout_contents->addLayout(l_form_flag);
|
||||
|
||||
|
|
@ -898,7 +911,8 @@ void HiddenItemFrame::setup() {
|
|||
QFormLayout *l_form_quantity = new QFormLayout(hideable_quantity);
|
||||
l_form_quantity->setContentsMargins(0, 0, 0, 0);
|
||||
this->spinner_quantity = new NoScrollSpinBox(hideable_quantity);
|
||||
this->spinner_quantity->setToolTip("The number of items received when the hidden item is picked up.");
|
||||
static const QString spinner_quantity_toolTip = Util::toHtmlParagraph("The number of items received when the hidden item is picked up.");
|
||||
this->spinner_quantity->setToolTip(spinner_quantity_toolTip);
|
||||
this->spinner_quantity->setMinimum(0x01);
|
||||
this->spinner_quantity->setMaximum(0xFF);
|
||||
l_form_quantity->addRow("Quantity", this->spinner_quantity);
|
||||
|
|
@ -909,7 +923,8 @@ void HiddenItemFrame::setup() {
|
|||
QFormLayout *l_form_itemfinder = new QFormLayout(hideable_itemfinder);
|
||||
l_form_itemfinder->setContentsMargins(0, 0, 0, 0);
|
||||
this->check_itemfinder = new QCheckBox(hideable_itemfinder);
|
||||
this->check_itemfinder->setToolTip("If checked, hidden item can only be picked up using the Itemfinder");
|
||||
static const QString check_itemfinder_toolTip = Util::toHtmlParagraph("If checked, hidden item can only be picked up using the Itemfinder");
|
||||
this->check_itemfinder->setToolTip(check_itemfinder_toolTip);
|
||||
l_form_itemfinder->addRow("Requires Itemfinder", this->check_itemfinder);
|
||||
this->layout_contents->addWidget(hideable_itemfinder);
|
||||
|
||||
|
|
@ -996,9 +1011,9 @@ void SecretBaseFrame::setup() {
|
|||
// item combo
|
||||
QFormLayout *l_form_base_id = new QFormLayout();
|
||||
this->combo_base_id = new NoScrollComboBox(this);
|
||||
this->combo_base_id->setToolTip("The secret base id which is inside this secret\n"
|
||||
"base entrance. Secret base ids are meant to be\n"
|
||||
"unique to each and every secret base entrance.");
|
||||
static const QString combo_base_id_toolTip = Util::toHtmlParagraph("The secret base id that is inside this secret base entrance. "
|
||||
"Secret base ids are meant to be unique to each and every secret base entrance.");
|
||||
this->combo_base_id->setToolTip(combo_base_id_toolTip);
|
||||
l_form_base_id->addRow("Secret Base", this->combo_base_id);
|
||||
this->layout_contents->addLayout(l_form_base_id);
|
||||
|
||||
|
|
@ -1048,7 +1063,8 @@ void HealLocationFrame::setup() {
|
|||
// ID
|
||||
QFormLayout *l_form_id = new QFormLayout();
|
||||
this->line_edit_id = new QLineEdit(this);
|
||||
this->line_edit_id->setToolTip("The unique identifier for this heal location.");
|
||||
static const QString line_edit_id_toolTip = Util::toHtmlParagraph("The unique identifier for this heal location.");
|
||||
this->line_edit_id->setToolTip(line_edit_id_toolTip);
|
||||
this->line_edit_id->setPlaceholderText(projectConfig.getIdentifier(ProjectIdentifier::define_heal_locations_prefix) + "MY_MAP");
|
||||
l_form_id->addRow("ID", this->line_edit_id);
|
||||
this->layout_contents->addLayout(l_form_id);
|
||||
|
|
@ -1058,7 +1074,8 @@ void HealLocationFrame::setup() {
|
|||
QFormLayout *l_form_respawn_map = new QFormLayout(hideable_respawn_map);
|
||||
l_form_respawn_map->setContentsMargins(0, 0, 0, 0);
|
||||
this->combo_respawn_map = new NoScrollComboBox(hideable_respawn_map);
|
||||
this->combo_respawn_map->setToolTip("The map where the player will respawn after whiteout.");
|
||||
static const QString combo_respawn_map_toolTip = Util::toHtmlParagraph("The map where the player will respawn after whiteout.");
|
||||
this->combo_respawn_map->setToolTip(combo_respawn_map_toolTip);
|
||||
l_form_respawn_map->addRow("Respawn Map", this->combo_respawn_map);
|
||||
this->layout_contents->addWidget(hideable_respawn_map);
|
||||
|
||||
|
|
@ -1067,8 +1084,9 @@ void HealLocationFrame::setup() {
|
|||
QFormLayout *l_form_respawn_npc = new QFormLayout(hideable_respawn_npc);
|
||||
l_form_respawn_npc->setContentsMargins(0, 0, 0, 0);
|
||||
this->combo_respawn_npc = new NoScrollComboBox(hideable_respawn_npc);
|
||||
this->combo_respawn_npc->setToolTip("The Local ID name or number of the NPC the player\n"
|
||||
"interacts with upon respawning after whiteout.");
|
||||
static const QString combo_respawn_npc_toolTip = Util::toHtmlParagraph("The Local ID name or number of the NPC the player "
|
||||
"interacts with upon respawning after whiteout.");
|
||||
this->combo_respawn_npc->setToolTip(combo_respawn_npc_toolTip);
|
||||
l_form_respawn_npc->addRow("Respawn NPC", this->combo_respawn_npc);
|
||||
this->layout_contents->addWidget(hideable_respawn_npc);
|
||||
|
||||
|
|
|
|||
|
|
@ -64,3 +64,12 @@ Overlay * MapView::getOverlay(int layer) {
|
|||
}
|
||||
return overlay;
|
||||
}
|
||||
|
||||
void ConnectionsView::keyPressEvent(QKeyEvent *event) {
|
||||
if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace) {
|
||||
emit pressedDelete();
|
||||
event->accept();
|
||||
} else {
|
||||
QGraphicsView::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
#include "ui_gridsettingsdialog.h"
|
||||
#include "gridsettings.h"
|
||||
|
||||
// TODO: Save settings in config
|
||||
|
||||
const QMap<GridSettings::Style, QString> GridSettings::styleToName = {
|
||||
{Style::Solid, "Solid"},
|
||||
{Style::LargeDashes, "Large Dashes"},
|
||||
|
|
|
|||
|
|
@ -174,19 +174,29 @@ void MapHeaderForm::updateLocationName() {
|
|||
}
|
||||
|
||||
// Set data in UI
|
||||
void MapHeaderForm::setSong(const QString &song) { ui->comboBox_Song->setCurrentText(song); }
|
||||
void MapHeaderForm::setLocation(const QString &location) { ui->comboBox_Location->setCurrentText(location); }
|
||||
void MapHeaderForm::setLocationName(const QString &locationName) { ui->lineEdit_LocationName->setText(locationName); }
|
||||
void MapHeaderForm::setSong(const QString &song) { setText(ui->comboBox_Song, song); }
|
||||
void MapHeaderForm::setLocation(const QString &location) { setText(ui->comboBox_Location, location); }
|
||||
void MapHeaderForm::setLocationName(const QString &locationName) { setText(ui->lineEdit_LocationName, locationName); }
|
||||
void MapHeaderForm::setRequiresFlash(bool requiresFlash) { ui->checkBox_RequiresFlash->setChecked(requiresFlash); }
|
||||
void MapHeaderForm::setWeather(const QString &weather) { ui->comboBox_Weather->setCurrentText(weather); }
|
||||
void MapHeaderForm::setType(const QString &type) { ui->comboBox_Type->setCurrentText(type); }
|
||||
void MapHeaderForm::setBattleScene(const QString &battleScene) { ui->comboBox_BattleScene->setCurrentText(battleScene); }
|
||||
void MapHeaderForm::setWeather(const QString &weather) { setText(ui->comboBox_Weather, weather); }
|
||||
void MapHeaderForm::setType(const QString &type) { setText(ui->comboBox_Type, type); }
|
||||
void MapHeaderForm::setBattleScene(const QString &battleScene) { setText(ui->comboBox_BattleScene, battleScene); }
|
||||
void MapHeaderForm::setShowsLocationName(bool showsLocationName) { ui->checkBox_ShowLocationName->setChecked(showsLocationName); }
|
||||
void MapHeaderForm::setAllowsRunning(bool allowsRunning) { ui->checkBox_AllowRunning->setChecked(allowsRunning); }
|
||||
void MapHeaderForm::setAllowsBiking(bool allowsBiking) { ui->checkBox_AllowBiking->setChecked(allowsBiking); }
|
||||
void MapHeaderForm::setAllowsEscaping(bool allowsEscaping) { ui->checkBox_AllowEscaping->setChecked(allowsEscaping); }
|
||||
void MapHeaderForm::setFloorNumber(int floorNumber) { ui->spinBox_FloorNumber->setValue(floorNumber); }
|
||||
|
||||
// If we always call setText / setCurrentText the user's cursor may move to the end of the text while they're typing.
|
||||
void MapHeaderForm::setText(QComboBox *combo, const QString &text) const {
|
||||
if (combo->currentText() != text)
|
||||
combo->setCurrentText(text);
|
||||
}
|
||||
void MapHeaderForm::setText(QLineEdit *lineEdit, const QString &text) const {
|
||||
if (lineEdit->text() != text)
|
||||
lineEdit->setText(text);
|
||||
}
|
||||
|
||||
// Read data from UI
|
||||
QString MapHeaderForm::song() const { return ui->comboBox_Song->currentText(); }
|
||||
QString MapHeaderForm::location() const { return ui->comboBox_Location->currentText(); }
|
||||
|
|
|
|||
|
|
@ -55,10 +55,7 @@ MapImageExporter::MapImageExporter(QWidget *parent, Project *project, Map *map,
|
|||
connect(ui->pushButton_Save, &QPushButton::pressed, this, &MapImageExporter::saveImage);
|
||||
connect(ui->pushButton_Cancel, &QPushButton::pressed, this, &MapImageExporter::close);
|
||||
|
||||
// Update the map selector when the text changes.
|
||||
// We don't use QComboBox::currentTextChanged to avoid unnecessary re-rendering.
|
||||
connect(ui->comboBox_MapSelection, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MapImageExporter::updateMapSelection);
|
||||
connect(ui->comboBox_MapSelection->lineEdit(), &QLineEdit::editingFinished, this, &MapImageExporter::updateMapSelection);
|
||||
connect(ui->comboBox_MapSelection, &NoScrollComboBox::editingFinished, this, &MapImageExporter::updateMapSelection);
|
||||
|
||||
connect(ui->checkBox_Objects, &QCheckBox::toggled, this, &MapImageExporter::setShowObjects);
|
||||
connect(ui->checkBox_Warps, &QCheckBox::toggled, this, &MapImageExporter::setShowWarps);
|
||||
|
|
@ -605,9 +602,7 @@ QPixmap MapImageExporter::getFormattedMapPixmap() {
|
|||
QMargins MapImageExporter::getMargins(const Map *map) {
|
||||
QMargins margins;
|
||||
if (m_settings.showBorder) {
|
||||
// The border may technically extend beyond BORDER_DISTANCE, but when the border is painted
|
||||
// we will be limiting it to the visible sight range.
|
||||
margins = QMargins(BORDER_DISTANCE, BORDER_DISTANCE, BORDER_DISTANCE, BORDER_DISTANCE) * 16;
|
||||
margins = m_project->getMetatileViewDistance() * 16;
|
||||
} else if (map && connectionsEnabled()) {
|
||||
for (const auto &connection : map->getConnections()) {
|
||||
const QString dir = connection->direction();
|
||||
|
|
@ -648,15 +643,12 @@ void MapImageExporter::paintBorder(QPainter *painter, Layout *layout) {
|
|||
layout->renderBorder(true);
|
||||
|
||||
// Clip parts of the border that would be beyond player visibility.
|
||||
QRect visibleArea(0, 0, layout->getWidth() * 16, layout->getHeight() * 16);
|
||||
visibleArea += (QMargins(BORDER_DISTANCE, BORDER_DISTANCE, BORDER_DISTANCE, BORDER_DISTANCE) * 16);
|
||||
painter->save();
|
||||
painter->setClipRect(visibleArea);
|
||||
painter->setClipRect(layout->getVisibleRect());
|
||||
|
||||
int borderHorzDist = layout->getBorderDrawWidth();
|
||||
int borderVertDist = layout->getBorderDrawHeight();
|
||||
for (int y = -borderVertDist; y < layout->getHeight() + borderVertDist; y += layout->getBorderHeight())
|
||||
for (int x = -borderHorzDist; x < layout->getWidth() + borderHorzDist; x += layout->getBorderWidth()) {
|
||||
const QMargins borderMargins = layout->getBorderMargins();
|
||||
for (int y = -borderMargins.top(); y < layout->getHeight() + borderMargins.bottom(); y += layout->getBorderHeight())
|
||||
for (int x = -borderMargins.left(); x < layout->getWidth() + borderMargins.right(); x += layout->getBorderWidth()) {
|
||||
// Skip border painting if it would be fully covered by the rest of the map
|
||||
if (layout->isWithinBounds(QRect(x, y, layout->getBorderWidth(), layout->getBorderHeight())))
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ void MapListToolBar::setEmptyFoldersVisible(bool visible) {
|
|||
}
|
||||
|
||||
// Update tool tip to reflect what will happen if the button is pressed.
|
||||
const QString toolTip = QString("%1 empty folders in the list.").arg(visible ? "Hide" : "Show");
|
||||
const QString toolTip = Util::toHtmlParagraph(QString("%1 empty folders in the list.").arg(visible ? "Hide" : "Show"));
|
||||
ui->button_ToggleEmptyFolders->setToolTip(toolTip);
|
||||
|
||||
const QSignalBlocker b(ui->button_ToggleEmptyFolders);
|
||||
|
|
@ -121,7 +121,9 @@ void MapListToolBar::applyFilter(const QString &filterText) {
|
|||
return;
|
||||
|
||||
const QSignalBlocker b(ui->lineEdit_filterBox);
|
||||
ui->lineEdit_filterBox->setText(filterText);
|
||||
if (ui->lineEdit_filterBox->text() != filterText) {
|
||||
ui->lineEdit_filterBox->setText(filterText);
|
||||
}
|
||||
|
||||
// The clear button does not properly disappear when filterText is empty.
|
||||
// It seems like this is because blocking the QLineEdit's signals prevents
|
||||
|
|
|
|||
|
|
@ -5,17 +5,21 @@
|
|||
#include "movablerect.h"
|
||||
#include "utility.h"
|
||||
|
||||
MovableRect::MovableRect(bool *enabled, int width, int height, QRgb color)
|
||||
: QGraphicsRectItem(0, 0, width, height)
|
||||
MovableRect::MovableRect(bool *enabled, const QRectF &rect, const QRgb &color)
|
||||
: QGraphicsRectItem(rect),
|
||||
enabled(enabled),
|
||||
baseRect(rect),
|
||||
color(color)
|
||||
{
|
||||
this->enabled = enabled;
|
||||
this->color = color;
|
||||
this->setVisible(*enabled);
|
||||
}
|
||||
|
||||
/// Center rect on grid position (x, y)
|
||||
void MovableRect::updateLocation(int x, int y) {
|
||||
this->setRect((x * 16) - this->rect().width() / 2 + 8, (y * 16) - this->rect().height() / 2 + 8, this->rect().width(), this->rect().height());
|
||||
this->setRect(this->baseRect.x() + (x * 16),
|
||||
this->baseRect.y() + (y * 16),
|
||||
this->baseRect.width(),
|
||||
this->baseRect.height());
|
||||
this->setVisible(*this->enabled);
|
||||
}
|
||||
|
||||
|
|
@ -25,7 +29,7 @@ void MovableRect::updateLocation(int x, int y) {
|
|||
|
||||
ResizableRect::ResizableRect(QObject *parent, bool *enabled, int width, int height, QRgb color)
|
||||
: QObject(parent),
|
||||
MovableRect(enabled, width * 16, height * 16, color)
|
||||
MovableRect(enabled, QRect(0, 0, width * 16, height * 16), color)
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
setFlags(this->flags() | QGraphicsItem::ItemIsMovable);
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ NewLayoutForm::NewLayoutForm(QWidget *parent)
|
|||
connect(ui->spinBox_MapWidth, QOverload<int>::of(&QSpinBox::valueChanged), [=](int){ validateMapDimensions(); });
|
||||
connect(ui->spinBox_MapHeight, QOverload<int>::of(&QSpinBox::valueChanged), [=](int){ validateMapDimensions(); });
|
||||
|
||||
connect(ui->comboBox_PrimaryTileset->lineEdit(), &QLineEdit::editingFinished, [this]{ validatePrimaryTileset(true); });
|
||||
connect(ui->comboBox_SecondaryTileset->lineEdit(), &QLineEdit::editingFinished, [this]{ validateSecondaryTileset(true); });
|
||||
connect(ui->comboBox_PrimaryTileset, &NoScrollComboBox::editingFinished, [this]{ validatePrimaryTileset(true); });
|
||||
connect(ui->comboBox_SecondaryTileset, &NoScrollComboBox::editingFinished, [this]{ validateSecondaryTileset(true); });
|
||||
}
|
||||
|
||||
NewLayoutForm::~NewLayoutForm()
|
||||
|
|
@ -86,17 +86,14 @@ bool NewLayoutForm::validateMapDimensions() {
|
|||
int size = m_project->getMapDataSize(ui->spinBox_MapWidth->value(), ui->spinBox_MapHeight->value());
|
||||
int maxSize = m_project->getMaxMapDataSize();
|
||||
|
||||
// TODO: Get from project
|
||||
const int additionalWidth = 15;
|
||||
const int additionalHeight = 14;
|
||||
|
||||
QString errorText;
|
||||
if (size > maxSize) {
|
||||
QSize addition = m_project->getMapSizeAddition();
|
||||
errorText = QString("The specified width and height are too large.\n"
|
||||
"The maximum map width and height is the following: (width + %1) * (height + %2) <= %3\n"
|
||||
"The specified map width and height was: (%4 + %1) * (%5 + %2) = %6")
|
||||
.arg(additionalWidth)
|
||||
.arg(additionalHeight)
|
||||
.arg(addition.width())
|
||||
.arg(addition.height())
|
||||
.arg(maxSize)
|
||||
.arg(ui->spinBox_MapWidth->value())
|
||||
.arg(ui->spinBox_MapHeight->value())
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
#include "newmapconnectiondialog.h"
|
||||
#include "ui_newmapconnectiondialog.h"
|
||||
#include "message.h"
|
||||
|
||||
NewMapConnectionDialog::NewMapConnectionDialog(QWidget *parent, Map* map, const QStringList &mapNames) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::NewMapConnectionDialog)
|
||||
ui(new Ui::NewMapConnectionDialog),
|
||||
m_map(map)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
ui->comboBox_Direction->setEditable(false);
|
||||
ui->comboBox_Direction->addItems(MapConnection::cardinalDirections);
|
||||
|
||||
ui->comboBox_Map->addItems(mapNames);
|
||||
|
|
@ -16,7 +17,7 @@ NewMapConnectionDialog::NewMapConnectionDialog(QWidget *parent, Map* map, const
|
|||
|
||||
// Choose default direction
|
||||
QMap<QString, int> directionCounts;
|
||||
for (auto connection : map->getConnections()) {
|
||||
for (auto connection : m_map->getConnections()) {
|
||||
directionCounts[connection->direction()]++;
|
||||
}
|
||||
QString defaultDirection;
|
||||
|
|
@ -33,7 +34,7 @@ NewMapConnectionDialog::NewMapConnectionDialog(QWidget *parent, Map* map, const
|
|||
QString defaultMapName;
|
||||
if (mapNames.isEmpty()) {
|
||||
defaultMapName = QString();
|
||||
} else if (mapNames.first() == map->name() && mapNames.length() > 1) {
|
||||
} else if (mapNames.first() == m_map->name() && mapNames.length() > 1) {
|
||||
// Prefer not to connect the map to itself
|
||||
defaultMapName = mapNames.at(1);
|
||||
} else {
|
||||
|
|
@ -62,11 +63,43 @@ void NewMapConnectionDialog::setWarningVisible(bool visible) {
|
|||
adjustSize();
|
||||
}
|
||||
|
||||
bool NewMapConnectionDialog::askReplaceConnection(MapConnection *connection, const QString &newMapName) {
|
||||
QString message = QString("%1 already has a %2 connection to '%3'. Replace it with a %2 connection to '%4'?")
|
||||
.arg(m_map->name())
|
||||
.arg(connection->direction())
|
||||
.arg(connection->targetMapName())
|
||||
.arg(newMapName);
|
||||
return QuestionMessage::show(message, this) == QMessageBox::Yes;
|
||||
}
|
||||
|
||||
void NewMapConnectionDialog::accept() {
|
||||
if (!mapNameIsValid()) {
|
||||
setWarningVisible(true);
|
||||
return;
|
||||
}
|
||||
emit accepted(new MapConnection(ui->comboBox_Map->currentText(), ui->comboBox_Direction->currentText()));
|
||||
|
||||
const QString direction = ui->comboBox_Direction->currentText();
|
||||
const QString targetMapName = ui->comboBox_Map->currentText();
|
||||
|
||||
// This is a very niche use case. Normally the user should add Dive/Emerge map connections using the line edits at the top of
|
||||
// the Connections tab, but because we allow custom direction names in this dialog's Direction drop-down, a user could type
|
||||
// in "dive" or "emerge" and we have to decide what to do. If there's no existing Dive/Emerge map we can just add it normally
|
||||
// as if they had typed in the regular line edits. If there's already an existing connection we need to replace it.
|
||||
if (MapConnection::isDiving(direction)) {
|
||||
MapConnection *connection = m_map->getConnection(direction);
|
||||
if (connection) {
|
||||
if (connection->targetMapName() != targetMapName) {
|
||||
if (!askReplaceConnection(connection, targetMapName))
|
||||
return; // Canceled
|
||||
emit connectionReplaced(targetMapName, direction);
|
||||
}
|
||||
// Replaced the diving connection (or no-op, if adding a diving connection with the same map name)
|
||||
QDialog::accept();
|
||||
return;
|
||||
}
|
||||
// Adding a new diving connection that doesn't exist yet, proceed normally.
|
||||
}
|
||||
|
||||
emit newConnectionedAdded(targetMapName, direction);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ NoScrollComboBox::NoScrollComboBox(QWidget *parent)
|
|||
static const QRegularExpression re("[^\\s]*");
|
||||
QValidator *validator = new QRegularExpressionValidator(re, this);
|
||||
this->setValidator(validator);
|
||||
|
||||
// QComboBox (as of writing) has no 'editing finished' signal to capture
|
||||
// changes made either through the text edit or the drop-down.
|
||||
connect(this, QOverload<int>::of(&QComboBox::activated), this, &NoScrollComboBox::editingFinished);
|
||||
connect(this->lineEdit(), &QLineEdit::editingFinished, this, &NoScrollComboBox::editingFinished);
|
||||
}
|
||||
|
||||
// On macOS QComboBox::setEditable and QComboBox::setLineEdit will override our changes to the focus policy, so we enforce it here.
|
||||
|
|
|
|||
|
|
@ -136,6 +136,12 @@ void ProjectSettingsEditor::initUi() {
|
|||
ui->spinBox_UnusedTileCovered->setMaximum(Tile::maxValue);
|
||||
ui->spinBox_UnusedTileSplit->setMaximum(Tile::maxValue);
|
||||
ui->spinBox_MaxEvents->setMaximum(INT_MAX);
|
||||
ui->spinBox_MapWidth->setMaximum(INT_MAX);
|
||||
ui->spinBox_MapHeight->setMaximum(INT_MAX);
|
||||
ui->spinBox_PlayerViewDistance_West->setMaximum(INT_MAX);
|
||||
ui->spinBox_PlayerViewDistance_North->setMaximum(INT_MAX);
|
||||
ui->spinBox_PlayerViewDistance_East->setMaximum(INT_MAX);
|
||||
ui->spinBox_PlayerViewDistance_South->setMaximum(INT_MAX);
|
||||
|
||||
// The values for some of the settings we provide in this window can be determined using constants in the user's projects.
|
||||
// If the user has these constants we disable these settings in the UI -- they can modify them using their constants.
|
||||
|
|
@ -167,7 +173,10 @@ void ProjectSettingsEditor::initUi() {
|
|||
bool ProjectSettingsEditor::disableParsedSetting(QWidget * widget, const QString &identifier, const QString &filepath) {
|
||||
if (project && project->disabledSettingsNames.contains(identifier)) {
|
||||
widget->setEnabled(false);
|
||||
widget->setToolTip(QString("This value has been set using '%1' in %2").arg(identifier).arg(filepath));
|
||||
QString toolTip = QString("This value has been set using '%1' in %2").arg(identifier).arg(filepath);
|
||||
if (!widget->toolTip().isEmpty())
|
||||
toolTip.prepend(QString("%1\n\n").arg(widget->toolTip()));
|
||||
widget->setToolTip(Util::toHtmlParagraph(toolTip));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -456,8 +465,10 @@ void ProjectSettingsEditor::refresh() {
|
|||
ui->spinBox_Elevation->setValue(projectConfig.defaultElevation);
|
||||
ui->spinBox_Collision->setValue(projectConfig.defaultCollision);
|
||||
ui->spinBox_FillMetatile->setValue(projectConfig.defaultMetatileId);
|
||||
ui->spinBox_MaxElevation->setValue(projectConfig.collisionSheetHeight - 1);
|
||||
ui->spinBox_MaxCollision->setValue(projectConfig.collisionSheetWidth - 1);
|
||||
ui->spinBox_MapWidth->setValue(projectConfig.defaultMapSize.width());
|
||||
ui->spinBox_MapHeight->setValue(projectConfig.defaultMapSize.height());
|
||||
ui->spinBox_MaxElevation->setValue(projectConfig.collisionSheetSize.height() - 1);
|
||||
ui->spinBox_MaxCollision->setValue(projectConfig.collisionSheetSize.width() - 1);
|
||||
ui->spinBox_BehaviorMask->setValue(projectConfig.metatileBehaviorMask & ui->spinBox_BehaviorMask->maximum());
|
||||
ui->spinBox_EncounterTypeMask->setValue(projectConfig.metatileEncounterTypeMask & ui->spinBox_EncounterTypeMask->maximum());
|
||||
ui->spinBox_LayerTypeMask->setValue(projectConfig.metatileLayerTypeMask & ui->spinBox_LayerTypeMask->maximum());
|
||||
|
|
@ -469,6 +480,10 @@ void ProjectSettingsEditor::refresh() {
|
|||
ui->spinBox_UnusedTileCovered->setValue(projectConfig.unusedTileCovered);
|
||||
ui->spinBox_UnusedTileSplit->setValue(projectConfig.unusedTileSplit);
|
||||
ui->spinBox_MaxEvents->setValue(projectConfig.maxEventsPerGroup);
|
||||
ui->spinBox_PlayerViewDistance_West->setValue(projectConfig.playerViewDistance.left());
|
||||
ui->spinBox_PlayerViewDistance_North->setValue(projectConfig.playerViewDistance.top());
|
||||
ui->spinBox_PlayerViewDistance_East->setValue(projectConfig.playerViewDistance.right());
|
||||
ui->spinBox_PlayerViewDistance_South->setValue(projectConfig.playerViewDistance.bottom());
|
||||
|
||||
// Set (and sync) border metatile IDs
|
||||
this->setBorderMetatileIds(false, projectConfig.newMapBorderMetatileIds);
|
||||
|
|
@ -532,8 +547,8 @@ void ProjectSettingsEditor::save() {
|
|||
projectConfig.defaultElevation = ui->spinBox_Elevation->value();
|
||||
projectConfig.defaultCollision = ui->spinBox_Collision->value();
|
||||
projectConfig.defaultMetatileId = ui->spinBox_FillMetatile->value();
|
||||
projectConfig.collisionSheetHeight = ui->spinBox_MaxElevation->value() + 1;
|
||||
projectConfig.collisionSheetWidth = ui->spinBox_MaxCollision->value() + 1;
|
||||
projectConfig.defaultMapSize = QSize(ui->spinBox_MapWidth->value(), ui->spinBox_MapHeight->value());
|
||||
projectConfig.collisionSheetSize = QSize(ui->spinBox_MaxElevation->value() + 1, ui->spinBox_MaxCollision->value() + 1);
|
||||
projectConfig.metatileBehaviorMask = ui->spinBox_BehaviorMask->value();
|
||||
projectConfig.metatileTerrainTypeMask = ui->spinBox_TerrainTypeMask->value();
|
||||
projectConfig.metatileEncounterTypeMask = ui->spinBox_EncounterTypeMask->value();
|
||||
|
|
@ -545,6 +560,10 @@ void ProjectSettingsEditor::save() {
|
|||
projectConfig.unusedTileCovered = ui->spinBox_UnusedTileCovered->value();
|
||||
projectConfig.unusedTileSplit = ui->spinBox_UnusedTileSplit->value();
|
||||
projectConfig.maxEventsPerGroup = ui->spinBox_MaxEvents->value();
|
||||
projectConfig.playerViewDistance = QMargins(ui->spinBox_PlayerViewDistance_West->value(),
|
||||
ui->spinBox_PlayerViewDistance_North->value(),
|
||||
ui->spinBox_PlayerViewDistance_East->value(),
|
||||
ui->spinBox_PlayerViewDistance_South->value());
|
||||
|
||||
// Save line edit settings
|
||||
projectConfig.prefabFilepath = ui->lineEdit_PrefabsPath->text();
|
||||
|
|
|
|||
|
|
@ -774,7 +774,10 @@ void RegionMapEditor::displayRegionMapTileSelector() {
|
|||
|
||||
this->mapsquare_selector_item = new TilemapTileSelector(this->region_map->pngPath(), this->region_map->tilemapFormat(), this->region_map->palPath());
|
||||
|
||||
this->mapsquare_selector_item->draw();
|
||||
// Initialize with current settings
|
||||
this->mapsquare_selector_item->selectHFlip(ui->checkBox_tileHFlip->isChecked());
|
||||
this->mapsquare_selector_item->selectVFlip(ui->checkBox_tileVFlip->isChecked());
|
||||
this->mapsquare_selector_item->selectPalette(ui->spinBox_tilePalette->value()); // This will also draw the selector
|
||||
|
||||
this->scene_region_map_tiles->addItem(this->mapsquare_selector_item);
|
||||
|
||||
|
|
|
|||
|
|
@ -146,15 +146,18 @@ void ResizeLayoutPopup::setupLayoutView() {
|
|||
// Upper limits: maximum metatiles in a map formula:
|
||||
// max = (width + 15) * (height + 14)
|
||||
// This limit can be found in fieldmap.c in pokeruby/pokeemerald/pokefirered.
|
||||
int numMetatiles = editor->project->getMapDataSize(rect.width() / 16, rect.height() / 16);
|
||||
int maxMetatiles = editor->project->getMaxMapDataSize();
|
||||
if (numMetatiles > maxMetatiles) {
|
||||
QString errorText = QString("The maximum layout width and height is the following: (width + 15) * (height + 14) <= %1\n"
|
||||
"The specified layout width and height was: (%2 + 15) * (%3 + 14) = %4")
|
||||
.arg(maxMetatiles)
|
||||
int size = editor->project->getMapDataSize(rect.width() / 16, rect.height() / 16);
|
||||
int maxSize = editor->project->getMaxMapDataSize();
|
||||
if (size > maxSize) {
|
||||
QSize addition = editor->project->getMapSizeAddition();
|
||||
QString errorText = QString("The maximum layout width and height is the following: (width + %1) * (height + %2) <= %3\n"
|
||||
"The specified layout width and height was: (%4 + %1) * (%5 + %2) = %6")
|
||||
.arg(addition.width())
|
||||
.arg(addition.height())
|
||||
.arg(maxSize)
|
||||
.arg(rect.width() / 16)
|
||||
.arg(rect.height() / 16)
|
||||
.arg(numMetatiles);
|
||||
.arg(size);
|
||||
QMessageBox warning;
|
||||
warning.setIcon(QMessageBox::Warning);
|
||||
warning.setText("The specified width and height are too large.");
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ TilesetEditor::TilesetEditor(Project *project, Layout *layout, QWidget *parent)
|
|||
this->tileYFlip = ui->checkBox_yFlip->isChecked();
|
||||
this->paletteId = ui->spinBox_paletteSelector->value();
|
||||
|
||||
connect(ui->actionSave_Tileset, &QAction::triggered, this, &TilesetEditor::save);
|
||||
|
||||
ui->actionShow_Tileset_Divider->setChecked(porymapConfig.showTilesetEditorDivider);
|
||||
ui->actionShow_Raw_Metatile_Attributes->setChecked(porymapConfig.showTilesetEditorRawAttributes);
|
||||
|
||||
|
|
@ -94,7 +96,7 @@ void TilesetEditor::updateTilesets(QString primaryTilesetLabel, QString secondar
|
|||
QMessageBox::No | QMessageBox::Yes,
|
||||
QMessageBox::Yes);
|
||||
if (result == QMessageBox::Yes)
|
||||
this->on_actionSave_Tileset_triggered();
|
||||
this->save();
|
||||
}
|
||||
this->setTilesets(primaryTilesetLabel, secondaryTilesetLabel);
|
||||
this->refresh();
|
||||
|
|
@ -125,16 +127,10 @@ void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTi
|
|||
}
|
||||
|
||||
void TilesetEditor::initAttributesUi() {
|
||||
// Update the metatile's attributes values when the attribute combo boxes are edited.
|
||||
// We avoid using the 'currentTextChanged' signal here, we want to know when we can clean up the input field and commit changes.
|
||||
connect(ui->comboBox_metatileBehaviors->lineEdit(), &QLineEdit::editingFinished, this, &TilesetEditor::commitMetatileBehavior);
|
||||
connect(ui->comboBox_encounterType->lineEdit(), &QLineEdit::editingFinished, this, &TilesetEditor::commitEncounterType);
|
||||
connect(ui->comboBox_terrainType->lineEdit(), &QLineEdit::editingFinished, this, &TilesetEditor::commitTerrainType);
|
||||
connect(ui->comboBox_layerType->lineEdit(), &QLineEdit::editingFinished, this, &TilesetEditor::commitLayerType);
|
||||
connect(ui->comboBox_metatileBehaviors, QOverload<int>::of(&QComboBox::activated), this, &TilesetEditor::commitMetatileBehavior);
|
||||
connect(ui->comboBox_encounterType, QOverload<int>::of(&QComboBox::activated), this, &TilesetEditor::commitEncounterType);
|
||||
connect(ui->comboBox_terrainType, QOverload<int>::of(&QComboBox::activated), this, &TilesetEditor::commitTerrainType);
|
||||
connect(ui->comboBox_layerType, QOverload<int>::of(&QComboBox::activated), this, &TilesetEditor::commitLayerType);
|
||||
connect(ui->comboBox_metatileBehaviors, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitMetatileBehavior);
|
||||
connect(ui->comboBox_encounterType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitEncounterType);
|
||||
connect(ui->comboBox_terrainType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitTerrainType);
|
||||
connect(ui->comboBox_layerType, &NoScrollComboBox::editingFinished, this, &TilesetEditor::commitLayerType);
|
||||
|
||||
// Behavior
|
||||
if (projectConfig.metatileBehaviorMask) {
|
||||
|
|
@ -688,19 +684,23 @@ void TilesetEditor::commitLayerType() {
|
|||
this->metatileSelector->drawSelectedMetatile(); // Changing the layer type can affect how fully transparent metatiles appear
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionSave_Tileset_triggered()
|
||||
{
|
||||
bool TilesetEditor::save() {
|
||||
// Need this temporary flag to stop selection resetting after saving.
|
||||
// This is a workaround; redrawing the map's metatile selector shouldn't emit the same signal as when it's selected.
|
||||
this->lockSelection = true;
|
||||
this->project->saveTilesets(this->primaryTileset, this->secondaryTileset);
|
||||
|
||||
bool success = this->project->saveTilesets(this->primaryTileset, this->secondaryTileset);
|
||||
emit this->tilesetsSaved(this->primaryTileset->name, this->secondaryTileset->name);
|
||||
if (this->paletteEditor) {
|
||||
this->paletteEditor->setTilesets(this->primaryTileset, this->secondaryTileset);
|
||||
}
|
||||
this->ui->statusbar->showMessage(QString("Saved primary and secondary Tilesets!"), 5000);
|
||||
this->hasUnsavedChanges = false;
|
||||
this->ui->statusbar->showMessage(success ? QStringLiteral("Saved primary and secondary Tilesets!")
|
||||
: QStringLiteral("Failed to save tilesets! See log for details."), 5000);
|
||||
if (success) {
|
||||
this->hasUnsavedChanges = false;
|
||||
}
|
||||
this->lockSelection = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionImport_Primary_Tiles_triggered()
|
||||
|
|
@ -812,8 +812,11 @@ void TilesetEditor::closeEvent(QCloseEvent *event)
|
|||
QMessageBox::Yes);
|
||||
|
||||
if (result == QMessageBox::Yes) {
|
||||
this->on_actionSave_Tileset_triggered();
|
||||
event->accept();
|
||||
if (this->save()) {
|
||||
event->accept();
|
||||
} else {
|
||||
event->ignore();
|
||||
}
|
||||
} else if (result == QMessageBox::No) {
|
||||
this->reset();
|
||||
event->accept();
|
||||
|
|
@ -1143,12 +1146,6 @@ void TilesetEditor::countMetatileUsage() {
|
|||
this->metatileSelector->usedMetatiles.fill(0);
|
||||
|
||||
for (auto layout : this->project->mapLayouts) {
|
||||
// It's possible for a layout's tileset labels to change if they are invalid,
|
||||
// so we need to load all the tilesets even if they aren't the tileset we're looking for.
|
||||
// Otherwise the metatile usage counts may change because the layouts with invalid tilesets
|
||||
// were updated to use a tileset we were looking for.
|
||||
this->project->loadLayoutTilesets(layout);
|
||||
|
||||
bool usesPrimary = (layout->tileset_primary_label == this->primaryTileset->name);
|
||||
bool usesSecondary = (layout->tileset_secondary_label == this->secondaryTileset->name);
|
||||
|
||||
|
|
@ -1187,10 +1184,10 @@ void TilesetEditor::countTileUsage() {
|
|||
QSet<Tileset*> secondaryTilesets;
|
||||
|
||||
for (auto &layout : this->project->mapLayouts) {
|
||||
this->project->loadLayoutTilesets(layout);
|
||||
if (layout->tileset_primary_label == this->primaryTileset->name
|
||||
|| layout->tileset_secondary_label == this->secondaryTileset->name) {
|
||||
// need to check metatiles
|
||||
this->project->loadLayoutTilesets(layout);
|
||||
if (layout->tileset_primary && layout->tileset_secondary) {
|
||||
primaryTilesets.insert(layout->tileset_primary);
|
||||
secondaryTilesets.insert(layout->tileset_secondary);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ void WildMonSearch::updateResults(const QString &species) {
|
|||
const QList<RowData> results = this->resultsCache.value(species, search(species));
|
||||
if (results.isEmpty()) {
|
||||
static const RowData noResults = {
|
||||
.mapName = "",
|
||||
.groupName = QStringLiteral("Species not found."),
|
||||
.fieldName = QStringLiteral("--"),
|
||||
.levelRange = QStringLiteral("--"),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user