Merge branch 'master' of https://github.com/huderlem/porymap into slam
This commit is contained in:
commit
815a16e8ca
84 changed files with 4880 additions and 3019 deletions
.github/workflows
CHANGELOG.mddocsrc/manual
forms
include
porymap.proresources
src
config.cpp
core
block.cppeditcommands.cppevents.cppheallocation.cppmap.cppmapconnection.cppmetatile.cppmetatileparser.cppnetwork.cppregionmap.cpptileset.cpp
editor.cppmainwindow.cppproject.cppscriptapi
ui
aboutporymap.cppcitymappixmapitem.cppconnectionpixmapitem.cppconnectionslistitem.cppcustomscriptseditor.cppdivingmappixmapitem.cppdraggablepixmapitem.cppencountertabledelegates.cppencountertablemodel.cppeventframes.cppimageproviders.cppmapimageexporter.cppmaplistmodels.cppmontabwidget.cppnewmapconnectiondialog.cppnewmappopup.cppnewtilesetdialog.cppnoscrollcombobox.cpppaletteeditor.cppprefab.cpppreferenceeditor.cppprojectsettingseditor.cppregionmapeditor.cppshortcutseditor.cpptileseteditor.cppupdatepromoter.cppwildmonchart.cpp
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
|
@ -33,7 +33,7 @@ jobs:
|
|||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: '5.14.2'
|
||||
modules: 'qtwidgets qtqml'
|
||||
modules: 'qtwidgets qtqml qtcharts'
|
||||
cached: ${{ steps.cache-qt.outputs.cache-hit }}
|
||||
|
||||
- name: Configure
|
||||
|
@ -58,7 +58,8 @@ jobs:
|
|||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '6.2.*'
|
||||
version: '6.7.*'
|
||||
modules: 'qtcharts'
|
||||
cached: ${{ steps.cache-qt.outputs.cache-hit }}
|
||||
|
||||
- name: Configure
|
||||
|
|
37
CHANGELOG.md
37
CHANGELOG.md
|
@ -7,7 +7,42 @@ and this project somewhat adheres to [Semantic Versioning](https://semver.org/sp
|
|||
The **"Breaking Changes"** listed below are changes that have been made in the decompilation projects (e.g. pokeemerald), which porymap requires in order to work properly. It also includes changes to the scripting API that may change the behavior of existing porymap scripts. If porymap is used with a project or API script that is not up-to-date with the breaking changes, then porymap will likely break or behave improperly.
|
||||
|
||||
## [Unreleased]
|
||||
Nothing, yet.
|
||||
### Added
|
||||
- Redesigned the Connections tab, adding a number of new features including the option to open or display diving maps and a list UI for easier edit access.
|
||||
- Add a `Close Project` option
|
||||
- Add charts to the `Wild Pokémon` tab that show species and level distributions.
|
||||
- An alert will be displayed when attempting to open a seemingly invalid project.
|
||||
|
||||
### Changed
|
||||
- Edits to map connections now have Undo/Redo and can be viewed in exported timelapses.
|
||||
- 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.
|
||||
|
||||
### Fixed
|
||||
- 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 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).
|
||||
- Fix selections with multiple Events not always clearing when making a new selection.
|
||||
- Fix `About porymap` opening a new window each time it's activated.
|
||||
- Fix the `Edit History` window not raising to the front when reactivated.
|
||||
- New maps are now always inserted in map dropdowns at the correct position, rather than at the bottom of the list until the project is reloaded.
|
||||
- Fix invalid species names clearing from wild pokémon data when revisited.
|
||||
- Fix editing wild pokémon data not marking the map as edited.
|
||||
- Fix changes to map connections not marking connected maps as unsaved.
|
||||
- Fix numerous issues related to connecting a map to itself.
|
||||
- Fix incorrect map connections getting selected when opening a map by double-clicking a map connection.
|
||||
- Fix a visual issue when quickly dragging map connections around.
|
||||
- Fix map connections rendering incorrectly if their direction name was unknown.
|
||||
- Fix map connections rendering incorrectly if their dimensions were smaller than the border draw distance.
|
||||
- Fix the map list filter retaining text between project open/close.
|
||||
- Fix the map list mishandling value gaps when sorting by Area.
|
||||
|
||||
## [5.4.1] - 2024-03-21
|
||||
### Fixed
|
||||
|
|
|
@ -2,35 +2,40 @@
|
|||
Editing Map Connections
|
||||
***********************
|
||||
|
||||
Maps can be connected together so that the player can seamlessly walk between them. These connections can be edited in the Connections tab.
|
||||
Maps can be connected together so that the player can seamlessly walk between them. These connections can be edited in the Connections tab.
|
||||
|
||||
.. figure:: images/editing-map-connections/map-connections.png
|
||||
:alt: Map Connections View
|
||||
|
||||
Map Connections View
|
||||
|
||||
A connection has a direction, offset, and destination map. To add new connection, press the plus button |add-connection-button|. To delete a connection, select it and press the delete button |remove-connection-button|.
|
||||
A connection has a direction, offset, and destination map. To add a new connection, press the |add-connection-button| button. To delete a connection you can either press the |remove-connection-button| button on its entry in the list, or select the connection and press the delete key.
|
||||
|
||||
The |open-connection-button| button will open the destination map. You may also open the destination map by double-clicking the connection itself (this can be done from the ``Map`` and ``Events`` tabs as well).
|
||||
|
||||
.. |add-connection-button|
|
||||
image:: images/editing-map-connections/add-connection-button.png
|
||||
:height: 24
|
||||
|
||||
.. |remove-connection-button|
|
||||
image:: images/editing-map-connections/remove-connection-button.png
|
||||
:height: 24
|
||||
|
||||
.. |open-connection-button|
|
||||
image:: images/editing-map-connections/open-connection-button.png
|
||||
:height: 24
|
||||
|
||||
To change the connection's vertical or horizontal offset, it's easiest to click and drag the connection to the desired offset.
|
||||
|
||||
Dive & Emerge Warps
|
||||
-------------------
|
||||
|
||||
Dive & emerge warps are used for the HM move Dive. They don't have offsets or directions--only a destination map. To add a dive or emerge warp, simply add a value in the Dive Map and/or Emerge Map dropdown menus.
|
||||
Dive & emerge warps are used for the HM move Dive. They don't have offsets or directions--only a destination map. To add a dive or emerge warp, simply add a value in the Dive Map and/or Emerge Map dropdown menus.
|
||||
|
||||
You can select the ``Show Emerge/Dive Maps`` checkbox to view your connected dive/emerge maps overlaid on the current map. The slider will change the opacity of this overlay. If you have both an emerge and a dive map connected you will see two sliders; the top slider is for the emerge map's opacity, and the bottom slider is for the dive map's opacity.
|
||||
|
||||
|
||||
Mirror Connections
|
||||
------------------
|
||||
|
||||
An extremely useful feature is the *Mirror to Connecting Maps* checkbox in the top-right corner. Connections are one-way, which means that you must keep the two connections in sync between the two maps. For example, Petalburg City has a west connection to Route 104, and Route 104 has an east connection to Petalburg City. If *Mirror to Connecting Maps* is enabled, then Porymap will automatically update both sides of the connection. Be sure to *File -> Save All* (``Ctrl+Shift+S``) when saving, since you will need to save both maps' connections.
|
||||
|
||||
Follow Connections
|
||||
------------------
|
||||
|
||||
Double-clicking on a connection will open the destination map. This is very useful for navigating through your maps, similar to double-clicking on :ref:`Warp Events <event-warps>`.
|
||||
|
|
Binary file not shown.
Before ![]() (image error) Size: 890 B After ![]() (image error) Size: 10 KiB ![]() ![]() |
Binary file not shown.
Before ![]() (image error) Size: 114 KiB After ![]() (image error) Size: 431 KiB ![]() ![]() |
Binary file not shown.
After ![]() (image error) Size: 5.5 KiB |
|
@ -67,6 +67,7 @@ The filepath that Porymap expects for each file can be overridden on the ``Files
|
|||
include/fieldmap.h, yes, no, ``constants_fieldmap``, reads tileset related constants
|
||||
src/fieldmap.c, yes, no, ``fieldmap``, reads ``symbol_attribute_table``
|
||||
src/event_object_movement.c, yes, no, ``initial_facing_table``, reads ``symbol_facing_directions``
|
||||
src/wild_encounter.c, yes, no, ``wild_encounter``, reads ``define_max_encounter_rate``
|
||||
src/pokemon_icon.c, yes, no, ``pokemon_icon_table``, reads files in ``symbol_pokemon_icon_table``
|
||||
graphics/pokemon/\*/icon.png, yes, no, ``pokemon_gfx``, to search for Pokémon icons if they aren't found in ``symbol_pokemon_icon_table``
|
||||
|
||||
|
@ -96,11 +97,13 @@ In addition to these files, there are some specific symbol and macro names that
|
|||
``define_obj_event_count``, ``OBJECT_EVENT_TEMPLATES_COUNT``, to limit total Object Events
|
||||
``define_min_level``, ``MIN_LEVEL``, minimum wild encounters level
|
||||
``define_max_level``, ``MAX_LEVEL``, maximum wild encounters level
|
||||
``define_max_encounter_rate``, ``MAX_ENCOUNTER_RATE``, this value / 16 will be the maximum encounter rate on the ``Wild Pokémon`` tab
|
||||
``define_tiles_primary``, ``NUM_TILES_IN_PRIMARY``,
|
||||
``define_tiles_total``, ``NUM_TILES_TOTAL``,
|
||||
``define_metatiles_primary``, ``NUM_METATILES_IN_PRIMARY``, total metatiles are calculated using metatile ID mask
|
||||
``define_pals_primary``, ``NUM_PALS_IN_PRIMARY``,
|
||||
``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_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
|
||||
|
@ -120,6 +123,7 @@ In addition to these files, there are some specific symbol and macro names that
|
|||
``define_map_section_prefix``, ``MAPSEC_``, expected prefix for location macro names
|
||||
``define_map_section_empty``, ``NONE``, macro name after prefix for empty region map sections
|
||||
``define_map_section_count``, ``COUNT``, macro name after prefix for total number of region map sections
|
||||
``define_species_prefix``, ``SPECIES_``, expected prefix for species macro names
|
||||
``regex_behaviors``, ``\bMB_``, regex to find metatile behavior macro names
|
||||
``regex_obj_event_gfx``, ``\bOBJ_EVENT_GFX_``, regex to find Object Event graphics ID macro names
|
||||
``regex_items``, ``\bITEM_(?!(B_)?USE_)``, regex to find item macro names
|
||||
|
@ -134,4 +138,3 @@ In addition to these files, there are some specific symbol and macro names that
|
|||
``regex_sign_facing_directions``, ``\bBG_EVENT_PLAYER_FACING_``, regex to find sign facing direction macro names
|
||||
``regex_trainer_types``, ``\bTRAINER_TYPE_``, regex to find trainer type macro names
|
||||
``regex_music``, ``\b(SE|MUS)_``, regex to find music macro names
|
||||
``regex_species``, ``\bSPECIES_``, regex to find species macro names
|
||||
|
|
132
forms/connectionslistitem.ui
Normal file
132
forms/connectionslistitem.ui
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConnectionsListItem</class>
|
||||
<widget class="QFrame" name="ConnectionsListItem">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>178</width>
|
||||
<height>157</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">.ConnectionsListItem { border-width: 1px; }</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_Map">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_Offset">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_Direction">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Direction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QToolButton" name="button_Delete">
|
||||
<property name="toolTip">
|
||||
<string>Remove this connection.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/delete.ico</normaloff>:/icons/delete.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<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>
|
||||
</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>
|
||||
</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>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QToolButton" name="button_OpenMap">
|
||||
<property name="toolTip">
|
||||
<string>Open the connected map.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/map_go.ico</normaloff>:/icons/map_go.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>NoScrollComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>noscrollcombobox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>NoScrollSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>noscrollspinbox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../resources/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -2090,8 +2090,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>85</width>
|
||||
<height>16</height>
|
||||
<width>100</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -2184,8 +2184,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>85</width>
|
||||
<height>16</height>
|
||||
<width>100</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -2278,8 +2278,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>85</width>
|
||||
<height>16</height>
|
||||
<width>100</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -2378,8 +2378,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>85</width>
|
||||
<height>16</height>
|
||||
<width>100</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -2472,8 +2472,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>85</width>
|
||||
<height>16</height>
|
||||
<width>100</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -2917,7 +2917,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item row="3" column="0">
|
||||
<widget class="QFrame" name="gridFrame">
|
||||
<widget class="QFrame" name="frame_Connections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -2930,24 +2930,9 @@
|
|||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_11">
|
||||
<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>
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QFrame" name="horizontalFrame">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_18">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_ConnectionsTopBar">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -2966,10 +2951,7 @@
|
|||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_10">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
|
@ -2982,82 +2964,20 @@
|
|||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_AddConnection">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item row="1" column="3">
|
||||
<widget class="NoScrollComboBox" name="comboBox_DiveMap">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Add a new connection.</p></body></html></string>
|
||||
<string><html><head/><body><p>Destination map name when using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<activeon>:/icons/add.ico</activeon>
|
||||
</iconset>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_RemoveConnection">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Remove the currently-selected connection.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<activeon>:/icons/delete.ico</activeon>
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Number of Connections:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_NumConnections">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_11">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<item row="0" column="7">
|
||||
<widget class="QCheckBox" name="checkBox_MirrorConnections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If enabled, connections will automatically be updated on the connected map.</p></body></html></string>
|
||||
<string>If enabled, connections will automatically be updated on the connected map.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Mirror to Connecting Maps</string>
|
||||
|
@ -3067,144 +2987,31 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QGraphicsView" name="graphicsView_Connections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="mouseTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustIgnored</enum>
|
||||
</property>
|
||||
<property name="dragMode">
|
||||
<enum>QGraphicsView::NoDrag</enum>
|
||||
</property>
|
||||
<property name="transformationAnchor">
|
||||
<enum>QGraphicsView::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
<property name="resizeAnchor">
|
||||
<enum>QGraphicsView::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QFrame" name="horizontalFrame2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,0,0,0,0,0">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_DiveMap">
|
||||
<property name="text">
|
||||
<string>Map</string>
|
||||
<string>Dive Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_ConnectedMap">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_EmergeMap">
|
||||
<property name="text">
|
||||
<string>Emerge Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="NoScrollComboBox" name="comboBox_EmergeMap">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The destination map name of the connection.</p></body></html></string>
|
||||
<string><html><head/><body><p>Destination map name when emerging using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Offset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spinBox_ConnectionOffset">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The number of metatiles to offset the connection.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-999</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_ConnectionDirection">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The direction of the connection.</p></body></html></string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>up</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>right</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>down</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>left</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="0" column="6">
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
|
@ -3217,87 +3024,274 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QToolButton" name="button_OpenDiveMap">
|
||||
<property name="toolTip">
|
||||
<string>Open the selected Dive Map</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/map_go.ico</normaloff>:/icons/map_go.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<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>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Show Emerge/Dive Maps</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<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>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget_DiveMapOpacity">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_OpacitySeparate">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
<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>
|
||||
<item>
|
||||
<widget class="QSlider" name="slider_EmergeMapOpacity">
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>90</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="slider_DiveMapOpacity">
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>90</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_OpacityCombined">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_20">
|
||||
<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>
|
||||
<item>
|
||||
<widget class="QSlider" name="slider_DiveEmergeMapOpacity">
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>90</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QToolButton" name="button_OpenEmergeMap">
|
||||
<property name="toolTip">
|
||||
<string>Open the selected Emerge Map</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/map_go.ico</normaloff>:/icons/map_go.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QFrame" name="horizontalFrame3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter_Connections">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
<widget class="QGraphicsView" name="graphicsView_Connections">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
<property name="mouseTracking">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Dive Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_DiveMap">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Destination map name when using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Emerge Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="NoScrollComboBox" name="comboBox_EmergeMap">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Destination map name when emerging using <span style=" font-weight:600;">Dive</span>. If empty, no such connection will exist.</p></body></html></string>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustIgnored</enum>
|
||||
</property>
|
||||
<property name="dragMode">
|
||||
<enum>QGraphicsView::NoDrag</enum>
|
||||
</property>
|
||||
<property name="transformationAnchor">
|
||||
<enum>QGraphicsView::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
<property name="resizeAnchor">
|
||||
<enum>QGraphicsView::AnchorUnderMouse</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QFrame" name="frame_EditConnectionsPanel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>230</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_17">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_AddConnection">
|
||||
<property name="text">
|
||||
<string>Add Connection</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/add.ico</normaloff>:/icons/add.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea_ConnectionsList">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaContents_ConnectionsList">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>365</width>
|
||||
<height>651</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="layout_ConnectionsList">
|
||||
<property name="spacing">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<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>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -3386,6 +3380,13 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_SummaryChart">
|
||||
<property name="text">
|
||||
<string>Summary Chart...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_ConfigureEncountersJSON">
|
||||
<property name="text">
|
||||
|
@ -3437,6 +3438,7 @@
|
|||
<addaction name="action_Open_Project"/>
|
||||
<addaction name="menuOpen_Recent_Project"/>
|
||||
<addaction name="action_Reload_Project"/>
|
||||
<addaction name="action_Close_Project"/>
|
||||
<addaction name="action_Save"/>
|
||||
<addaction name="action_Save_Project"/>
|
||||
<addaction name="separator"/>
|
||||
|
@ -3460,6 +3462,7 @@
|
|||
<addaction name="actionCursor_Tile_Outline"/>
|
||||
<addaction name="actionPlayer_View_Rectangle"/>
|
||||
<addaction name="actionBetter_Cursors"/>
|
||||
<addaction name="actionDive_Emerge_Map"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
|
@ -3791,6 +3794,25 @@
|
|||
<enum>QAction::ApplicationSpecificRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Close_Project">
|
||||
<property name="text">
|
||||
<string>Close Project</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+W</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDive_Emerge_Map">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dive/Emerge Map</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
|
136
forms/newmapconnectiondialog.ui
Normal file
136
forms/newmapconnectiondialog.ui
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>NewMapConnectionDialog</class>
|
||||
<widget class="QDialog" name="NewMapConnectionDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>234</width>
|
||||
<height>162</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Add New Map Connection</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<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>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_Map">
|
||||
<property name="text">
|
||||
<string>Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<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>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_Direction">
|
||||
<property name="text">
|
||||
<string>Direction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<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>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_Warning">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(255, 0, 0)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>'Map' must be the name of an existing map.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>NoScrollComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>noscrollcombobox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>NewMapConnectionDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>NewMapConnectionDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
245
forms/wildmonchart.ui
Normal file
245
forms/wildmonchart.ui
Normal file
|
@ -0,0 +1,245 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>WildMonChart</class>
|
||||
<widget class="QWidget" name="WildMonChart">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>785</width>
|
||||
<height>492</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Wild Pokémon Summary</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_TopBar">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<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>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_Theme">
|
||||
<property name="text">
|
||||
<string>Theme</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox_Theme"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="button_Help">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/images.qrc">
|
||||
<normaloff>:/icons/help.ico</normaloff>:/icons/help.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabSpecies">
|
||||
<attribute name="title">
|
||||
<string>Species Distribution</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QChartView" name="chartView_SpeciesDistribution">
|
||||
<property name="renderHints">
|
||||
<set>QPainter::Antialiasing</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabLevels">
|
||||
<attribute name="title">
|
||||
<string>Level Distribution</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_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>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="topMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_Group">
|
||||
<property name="text">
|
||||
<string>Group</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox_Group">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_Species">
|
||||
<property name="title">
|
||||
<string>Individual Mode</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_Species">
|
||||
<property name="text">
|
||||
<string>Species</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="comboBox_Species">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::NoInsert</enum>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>12</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QChartView" name="chartView_LevelDistribution">
|
||||
<property name="renderHints">
|
||||
<set>QPainter::Antialiasing</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QChartView</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>QtCharts</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../resources/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
314
include/config.h
314
include/config.h
|
@ -33,20 +33,17 @@ class KeyValueConfigBase
|
|||
public:
|
||||
void save();
|
||||
void load();
|
||||
void setSaveDisabled(bool disabled);
|
||||
virtual ~KeyValueConfigBase();
|
||||
virtual void reset() = 0;
|
||||
protected:
|
||||
virtual QString getConfigFilepath() = 0;
|
||||
virtual void parseConfigKeyValue(QString key, QString value) = 0;
|
||||
virtual QMap<QString, QString> getKeyValueMap() = 0;
|
||||
virtual void onNewConfigFileCreated() = 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);
|
||||
private:
|
||||
bool saveDisabled = false;
|
||||
};
|
||||
|
||||
class PorymapConfig: public KeyValueConfigBase
|
||||
|
@ -57,9 +54,15 @@ public:
|
|||
}
|
||||
virtual void reset() override {
|
||||
this->recentProjects.clear();
|
||||
this->projectManuallyClosed = false;
|
||||
this->reopenOnLaunch = true;
|
||||
this->mapSortOrder = MapSortOrder::SortByGroup;
|
||||
this->prettyCursors = true;
|
||||
this->mirrorConnectingMaps = true;
|
||||
this->showDiveEmergeMaps = false;
|
||||
this->diveEmergeMapOpacity = 30;
|
||||
this->diveMapOpacity = 15;
|
||||
this->emergeMapOpacity = 15;
|
||||
this->collisionOpacity = 50;
|
||||
this->collisionZoom = 30;
|
||||
this->metatilesZoom = 30;
|
||||
|
@ -74,6 +77,7 @@ public:
|
|||
this->monitorFiles = true;
|
||||
this->tilesetCheckerboardFill = true;
|
||||
this->theme = "default";
|
||||
this->wildMonChartTheme = "";
|
||||
this->textEditorOpenFolder = "";
|
||||
this->textEditorGotoLine = "";
|
||||
this->paletteEditorBitDepth = 24;
|
||||
|
@ -86,85 +90,68 @@ public:
|
|||
}
|
||||
void addRecentProject(QString project);
|
||||
void setRecentProjects(QStringList projects);
|
||||
void setReopenOnLaunch(bool enabled);
|
||||
void setMapSortOrder(MapSortOrder order);
|
||||
void setPrettyCursors(bool enabled);
|
||||
QString getRecentProject();
|
||||
QStringList getRecentProjects();
|
||||
void setMainGeometry(QByteArray, QByteArray, QByteArray, QByteArray, QByteArray);
|
||||
void setTilesetEditorGeometry(QByteArray, QByteArray, QByteArray);
|
||||
void setPaletteEditorGeometry(QByteArray, QByteArray);
|
||||
void setRegionMapEditorGeometry(QByteArray, QByteArray);
|
||||
void setProjectSettingsEditorGeometry(QByteArray, QByteArray);
|
||||
void setCustomScriptsEditorGeometry(QByteArray, QByteArray);
|
||||
void setCollisionOpacity(int opacity);
|
||||
void setCollisionZoom(int zoom);
|
||||
void setMetatilesZoom(int zoom);
|
||||
void setTilesetEditorMetatilesZoom(int zoom);
|
||||
void setTilesetEditorTilesZoom(int zoom);
|
||||
void setShowPlayerView(bool enabled);
|
||||
void setShowCursorTile(bool enabled);
|
||||
void setShowBorder(bool enabled);
|
||||
void setShowGrid(bool enabled);
|
||||
void setShowTilesetEditorMetatileGrid(bool enabled);
|
||||
void setShowTilesetEditorLayerGrid(bool enabled);
|
||||
void setMonitorFiles(bool monitor);
|
||||
void setTilesetCheckerboardFill(bool checkerboard);
|
||||
void setTheme(QString theme);
|
||||
void setTextEditorOpenFolder(const QString &command);
|
||||
void setTextEditorGotoLine(const QString &command);
|
||||
void setPaletteEditorBitDepth(int bitDepth);
|
||||
void setProjectSettingsTab(int tab);
|
||||
void setWarpBehaviorWarningDisabled(bool disabled);
|
||||
void setCheckForUpdates(bool enabled);
|
||||
void setLastUpdateCheckTime(QDateTime time);
|
||||
void setLastUpdateCheckVersion(QVersionNumber version);
|
||||
void setRateLimitTimes(QMap<QUrl, QDateTime> map);
|
||||
QString getRecentProject();
|
||||
QStringList getRecentProjects();
|
||||
bool getReopenOnLaunch();
|
||||
MapSortOrder getMapSortOrder();
|
||||
bool getPrettyCursors();
|
||||
QMap<QString, QByteArray> getMainGeometry();
|
||||
QMap<QString, QByteArray> getTilesetEditorGeometry();
|
||||
QMap<QString, QByteArray> getPaletteEditorGeometry();
|
||||
QMap<QString, QByteArray> getRegionMapEditorGeometry();
|
||||
QMap<QString, QByteArray> getProjectSettingsEditorGeometry();
|
||||
QMap<QString, QByteArray> getCustomScriptsEditorGeometry();
|
||||
int getCollisionOpacity();
|
||||
int getCollisionZoom();
|
||||
int getMetatilesZoom();
|
||||
int getTilesetEditorMetatilesZoom();
|
||||
int getTilesetEditorTilesZoom();
|
||||
bool getShowPlayerView();
|
||||
bool getShowCursorTile();
|
||||
bool getShowBorder();
|
||||
bool getShowGrid();
|
||||
bool getShowTilesetEditorMetatileGrid();
|
||||
bool getShowTilesetEditorLayerGrid();
|
||||
bool getMonitorFiles();
|
||||
bool getTilesetCheckerboardFill();
|
||||
QString getTheme();
|
||||
QString getTextEditorOpenFolder();
|
||||
QString getTextEditorGotoLine();
|
||||
int getPaletteEditorBitDepth();
|
||||
int getProjectSettingsTab();
|
||||
bool getWarpBehaviorWarningDisabled();
|
||||
bool getCheckForUpdates();
|
||||
QDateTime getLastUpdateCheckTime();
|
||||
QVersionNumber getLastUpdateCheckVersion();
|
||||
QMap<QUrl, QDateTime> getRateLimitTimes();
|
||||
|
||||
bool reopenOnLaunch;
|
||||
bool projectManuallyClosed;
|
||||
MapSortOrder mapSortOrder;
|
||||
bool prettyCursors;
|
||||
bool mirrorConnectingMaps;
|
||||
bool showDiveEmergeMaps;
|
||||
int diveEmergeMapOpacity;
|
||||
int diveMapOpacity;
|
||||
int emergeMapOpacity;
|
||||
int collisionOpacity;
|
||||
int collisionZoom;
|
||||
int metatilesZoom;
|
||||
int tilesetEditorMetatilesZoom;
|
||||
int tilesetEditorTilesZoom;
|
||||
bool showPlayerView;
|
||||
bool showCursorTile;
|
||||
bool showBorder;
|
||||
bool showGrid;
|
||||
bool showTilesetEditorMetatileGrid;
|
||||
bool showTilesetEditorLayerGrid;
|
||||
bool monitorFiles;
|
||||
bool tilesetCheckerboardFill;
|
||||
QString theme;
|
||||
QString wildMonChartTheme;
|
||||
QString textEditorOpenFolder;
|
||||
QString textEditorGotoLine;
|
||||
int paletteEditorBitDepth;
|
||||
int projectSettingsTab;
|
||||
bool warpBehaviorWarningDisabled;
|
||||
bool checkForUpdates;
|
||||
QDateTime lastUpdateCheckTime;
|
||||
QVersionNumber lastUpdateCheckVersion;
|
||||
QMap<QUrl, QDateTime> rateLimitTimes;
|
||||
QByteArray wildMonChartGeometry;
|
||||
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
virtual void parseConfigKeyValue(QString key, QString value) override;
|
||||
virtual QMap<QString, QString> getKeyValueMap() override;
|
||||
virtual void onNewConfigFileCreated() override {};
|
||||
virtual void init() override {};
|
||||
virtual void setUnreadKeys() override {};
|
||||
|
||||
private:
|
||||
QStringList recentProjects;
|
||||
bool reopenOnLaunch;
|
||||
QString stringFromByteArray(QByteArray);
|
||||
QByteArray bytesFromString(QString);
|
||||
MapSortOrder mapSortOrder;
|
||||
bool prettyCursors;
|
||||
|
||||
QStringList recentProjects;
|
||||
QByteArray mainWindowGeometry;
|
||||
QByteArray mainWindowState;
|
||||
QByteArray mapSplitterState;
|
||||
|
@ -181,34 +168,12 @@ private:
|
|||
QByteArray projectSettingsEditorState;
|
||||
QByteArray customScriptsEditorGeometry;
|
||||
QByteArray customScriptsEditorState;
|
||||
int collisionOpacity;
|
||||
int collisionZoom;
|
||||
int metatilesZoom;
|
||||
int tilesetEditorMetatilesZoom;
|
||||
int tilesetEditorTilesZoom;
|
||||
bool showPlayerView;
|
||||
bool showCursorTile;
|
||||
bool showBorder;
|
||||
bool showGrid;
|
||||
bool showTilesetEditorMetatileGrid;
|
||||
bool showTilesetEditorLayerGrid;
|
||||
bool monitorFiles;
|
||||
bool tilesetCheckerboardFill;
|
||||
QString theme;
|
||||
QString textEditorOpenFolder;
|
||||
QString textEditorGotoLine;
|
||||
int paletteEditorBitDepth;
|
||||
int projectSettingsTab;
|
||||
bool warpBehaviorWarningDisabled;
|
||||
bool checkForUpdates;
|
||||
QDateTime lastUpdateCheckTime;
|
||||
QVersionNumber lastUpdateCheckVersion;
|
||||
QMap<QUrl, QDateTime> rateLimitTimes;
|
||||
};
|
||||
|
||||
extern PorymapConfig porymapConfig;
|
||||
|
||||
enum BaseGameVersion {
|
||||
none,
|
||||
pokeruby,
|
||||
pokefirered,
|
||||
pokeemerald,
|
||||
|
@ -229,11 +194,13 @@ enum ProjectIdentifier {
|
|||
define_obj_event_count,
|
||||
define_min_level,
|
||||
define_max_level,
|
||||
define_max_encounter_rate,
|
||||
define_tiles_primary,
|
||||
define_tiles_total,
|
||||
define_metatiles_primary,
|
||||
define_pals_primary,
|
||||
define_pals_total,
|
||||
define_tiles_per_metatile,
|
||||
define_map_size,
|
||||
define_mask_metatile,
|
||||
define_mask_collision,
|
||||
|
@ -253,6 +220,7 @@ enum ProjectIdentifier {
|
|||
define_map_section_prefix,
|
||||
define_map_section_empty,
|
||||
define_map_section_count,
|
||||
define_species_prefix,
|
||||
regex_behaviors,
|
||||
regex_obj_event_gfx,
|
||||
regex_items,
|
||||
|
@ -267,7 +235,6 @@ enum ProjectIdentifier {
|
|||
regex_sign_facing_directions,
|
||||
regex_trainer_types,
|
||||
regex_music,
|
||||
regex_species,
|
||||
};
|
||||
|
||||
enum ProjectFilePath {
|
||||
|
@ -316,6 +283,7 @@ enum ProjectFilePath {
|
|||
global_fieldmap,
|
||||
fieldmap,
|
||||
initial_facing_table,
|
||||
wild_encounter,
|
||||
pokemon_icon_table,
|
||||
pokemon_gfx,
|
||||
};
|
||||
|
@ -330,7 +298,7 @@ public:
|
|||
this->baseGameVersion = BaseGameVersion::pokeemerald;
|
||||
// Reset non-version-specific settings
|
||||
this->usePoryScript = false;
|
||||
this->enableTripleLayerMetatiles = false;
|
||||
this->tripleLayerMetatilesEnabled = false;
|
||||
this->defaultMetatileId = 1;
|
||||
this->defaultElevation = 3;
|
||||
this->defaultCollision = 0;
|
||||
|
@ -354,52 +322,11 @@ public:
|
|||
static const QMap<ProjectIdentifier, QPair<QString, QString>> defaultIdentifiers;
|
||||
static const QMap<ProjectFilePath, QPair<QString, QString>> defaultPaths;
|
||||
static const QStringList versionStrings;
|
||||
static BaseGameVersion stringToBaseGameVersion(const QString &string);
|
||||
|
||||
void reset(BaseGameVersion baseGameVersion);
|
||||
void setBaseGameVersion(BaseGameVersion baseGameVersion);
|
||||
BaseGameVersion getBaseGameVersion();
|
||||
QString getBaseGameVersionString();
|
||||
QString getBaseGameVersionString(BaseGameVersion version);
|
||||
BaseGameVersion stringToBaseGameVersion(QString string, bool * ok = nullptr);
|
||||
void setUsePoryScript(bool usePoryScript);
|
||||
bool getUsePoryScript();
|
||||
void setProjectDir(QString projectDir);
|
||||
QString getProjectDir();
|
||||
void setUseCustomBorderSize(bool enable);
|
||||
bool getUseCustomBorderSize();
|
||||
void setEventWeatherTriggerEnabled(bool enable);
|
||||
bool getEventWeatherTriggerEnabled();
|
||||
void setEventSecretBaseEnabled(bool enable);
|
||||
bool getEventSecretBaseEnabled();
|
||||
void setHiddenItemQuantityEnabled(bool enable);
|
||||
bool getHiddenItemQuantityEnabled();
|
||||
void setHiddenItemRequiresItemfinderEnabled(bool enable);
|
||||
bool getHiddenItemRequiresItemfinderEnabled();
|
||||
void setHealLocationRespawnDataEnabled(bool enable);
|
||||
bool getHealLocationRespawnDataEnabled();
|
||||
void setEventCloneObjectEnabled(bool enable);
|
||||
bool getEventCloneObjectEnabled();
|
||||
void setFloorNumberEnabled(bool enable);
|
||||
bool getFloorNumberEnabled();
|
||||
void setCreateMapTextFileEnabled(bool enable);
|
||||
bool getCreateMapTextFileEnabled();
|
||||
void setTripleLayerMetatilesEnabled(bool enable);
|
||||
bool getTripleLayerMetatilesEnabled();
|
||||
int getNumLayersInMetatile();
|
||||
int getNumTilesInMetatile();
|
||||
void setDefaultMetatileId(uint16_t metatileId);
|
||||
uint16_t getDefaultMetatileId();
|
||||
void setDefaultElevation(uint16_t elevation);
|
||||
uint16_t getDefaultElevation();
|
||||
void setDefaultCollision(uint16_t collision);
|
||||
uint16_t getDefaultCollision();
|
||||
void setNewMapBorderMetatileIds(QList<uint16_t> metatileIds);
|
||||
QList<uint16_t> getNewMapBorderMetatileIds();
|
||||
QString getDefaultPrimaryTileset();
|
||||
QString getDefaultSecondaryTileset();
|
||||
void setDefaultPrimaryTileset(QString tilesetName);
|
||||
void setDefaultSecondaryTileset(QString tilesetName);
|
||||
void setFilePath(const QString &pathId, const QString &path);
|
||||
void setFilePath(ProjectFilePath pathId, const QString &path);
|
||||
void setFilePath(const QString &pathId, const QString &path);
|
||||
QString getCustomFilePath(ProjectFilePath pathId);
|
||||
QString getCustomFilePath(const QString &pathId);
|
||||
QString getFilePath(ProjectFilePath pathId);
|
||||
|
@ -408,75 +335,35 @@ public:
|
|||
QString getCustomIdentifier(ProjectIdentifier id);
|
||||
QString getCustomIdentifier(const QString &id);
|
||||
QString getIdentifier(ProjectIdentifier id);
|
||||
void setPrefabFilepath(QString filepath);
|
||||
QString getPrefabFilepath();
|
||||
void setPrefabImportPrompted(bool prompted);
|
||||
bool getPrefabImportPrompted();
|
||||
void setTilesetsHaveCallback(bool has);
|
||||
bool getTilesetsHaveCallback();
|
||||
void setTilesetsHaveIsCompressed(bool has);
|
||||
bool getTilesetsHaveIsCompressed();
|
||||
int getMetatileAttributesSize();
|
||||
void setMetatileAttributesSize(int size);
|
||||
uint32_t getMetatileBehaviorMask();
|
||||
uint32_t getMetatileTerrainTypeMask();
|
||||
uint32_t getMetatileEncounterTypeMask();
|
||||
uint32_t getMetatileLayerTypeMask();
|
||||
void setMetatileBehaviorMask(uint32_t mask);
|
||||
void setMetatileTerrainTypeMask(uint32_t mask);
|
||||
void setMetatileEncounterTypeMask(uint32_t mask);
|
||||
void setMetatileLayerTypeMask(uint32_t mask);
|
||||
uint16_t getBlockMetatileIdMask();
|
||||
uint16_t getBlockCollisionMask();
|
||||
uint16_t getBlockElevationMask();
|
||||
void setBlockMetatileIdMask(uint16_t mask);
|
||||
void setBlockCollisionMask(uint16_t mask);
|
||||
void setBlockElevationMask(uint16_t mask);
|
||||
bool getMapAllowFlagsEnabled();
|
||||
void setMapAllowFlagsEnabled(bool enabled);
|
||||
QString getBaseGameVersionString(BaseGameVersion version);
|
||||
QString getBaseGameVersionString();
|
||||
int getNumLayersInMetatile();
|
||||
int getNumTilesInMetatile();
|
||||
void setEventIconPath(Event::Group group, const QString &path);
|
||||
QString getEventIconPath(Event::Group group);
|
||||
void setPokemonIconPath(const QString &species, const QString &path);
|
||||
QString getPokemonIconPath(const QString &species);
|
||||
QHash<QString, QString> getPokemonIconPaths();
|
||||
void setCollisionSheetPath(const QString &path);
|
||||
QString getCollisionSheetPath();
|
||||
void setCollisionSheetWidth(int width);
|
||||
int getCollisionSheetWidth();
|
||||
void setCollisionSheetHeight(int height);
|
||||
int getCollisionSheetHeight();
|
||||
void setWarpBehaviors(const QSet<uint32_t> &behaviors);
|
||||
QSet<uint32_t> getWarpBehaviors();
|
||||
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
virtual void parseConfigKeyValue(QString key, QString value) override;
|
||||
virtual QMap<QString, QString> getKeyValueMap() override;
|
||||
virtual void onNewConfigFileCreated() override;
|
||||
virtual void setUnreadKeys() override;
|
||||
private:
|
||||
BaseGameVersion baseGameVersion;
|
||||
QString projectDir;
|
||||
QMap<ProjectIdentifier, QString> identifiers;
|
||||
QMap<ProjectFilePath, QString> filePaths;
|
||||
bool usePoryScript;
|
||||
bool useCustomBorderSize;
|
||||
bool enableEventWeatherTrigger;
|
||||
bool enableEventSecretBase;
|
||||
bool enableHiddenItemQuantity;
|
||||
bool enableHiddenItemRequiresItemfinder;
|
||||
bool enableHealLocationRespawnData;
|
||||
bool enableEventCloneObject;
|
||||
bool enableFloorNumber;
|
||||
bool createMapTextFile;
|
||||
bool enableTripleLayerMetatiles;
|
||||
bool eventWeatherTriggerEnabled;
|
||||
bool eventSecretBaseEnabled;
|
||||
bool hiddenItemQuantityEnabled;
|
||||
bool hiddenItemRequiresItemfinderEnabled;
|
||||
bool healLocationRespawnDataEnabled;
|
||||
bool eventCloneObjectEnabled;
|
||||
bool floorNumberEnabled;
|
||||
bool createMapTextFileEnabled;
|
||||
bool tripleLayerMetatilesEnabled;
|
||||
uint16_t defaultMetatileId;
|
||||
uint16_t defaultElevation;
|
||||
uint16_t defaultCollision;
|
||||
QList<uint16_t> newMapBorderMetatileIds;
|
||||
QString defaultPrimaryTileset;
|
||||
QString defaultSecondaryTileset;
|
||||
QStringList readKeys;
|
||||
QString prefabFilepath;
|
||||
bool prefabImportPrompted;
|
||||
bool tilesetsHaveCallback;
|
||||
|
@ -489,13 +376,25 @@ private:
|
|||
uint16_t blockMetatileIdMask;
|
||||
uint16_t blockCollisionMask;
|
||||
uint16_t blockElevationMask;
|
||||
bool enableMapAllowFlags;
|
||||
QMap<Event::Group, QString> eventIconPaths;
|
||||
QHash<QString, QString> pokemonIconPaths;
|
||||
bool mapAllowFlagsEnabled;
|
||||
QString collisionSheetPath;
|
||||
int collisionSheetWidth;
|
||||
int collisionSheetHeight;
|
||||
QSet<uint32_t> warpBehaviors;
|
||||
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
virtual void parseConfigKeyValue(QString key, QString value) override;
|
||||
virtual QMap<QString, QString> getKeyValueMap() override;
|
||||
virtual void init() override;
|
||||
virtual void setUnreadKeys() override;
|
||||
|
||||
private:
|
||||
QStringList readKeys;
|
||||
QMap<ProjectIdentifier, QString> identifiers;
|
||||
QMap<ProjectFilePath, QString> filePaths;
|
||||
QMap<Event::Group, QString> eventIconPaths;
|
||||
QHash<QString, QString> pokemonIconPaths;
|
||||
};
|
||||
|
||||
extern ProjectConfig projectConfig;
|
||||
|
@ -513,35 +412,30 @@ public:
|
|||
this->customScripts.clear();
|
||||
this->readKeys.clear();
|
||||
}
|
||||
void setRecentMap(const QString &map);
|
||||
QString getRecentMap();
|
||||
void setRecentLayout(const QString &map);
|
||||
QString getRecentLayout();
|
||||
void setEncounterJsonActive(bool active);
|
||||
bool getEncounterJsonActive();
|
||||
void setProjectDir(QString projectDir);
|
||||
QString getProjectDir();
|
||||
void parseCustomScripts(QString input);
|
||||
QString outputCustomScripts();
|
||||
void setCustomScripts(QStringList scripts, QList<bool> enabled);
|
||||
QStringList getCustomScriptPaths();
|
||||
QList<bool> getCustomScriptsEnabled();
|
||||
void parseCustomScripts(QString input);
|
||||
QString outputCustomScripts();
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
virtual void parseConfigKeyValue(QString key, QString value) override;
|
||||
virtual QMap<QString, QString> getKeyValueMap() override;
|
||||
virtual void onNewConfigFileCreated() override;
|
||||
virtual void setUnreadKeys() override;
|
||||
#ifdef CONFIG_BACKWARDS_COMPATABILITY
|
||||
friend class ProjectConfig;
|
||||
#endif
|
||||
private:
|
||||
|
||||
QString projectDir;
|
||||
QString recentMap;
|
||||
QString recentLayout;
|
||||
bool useEncounterJson;
|
||||
QMap<QString, bool> customScripts;
|
||||
|
||||
protected:
|
||||
virtual QString getConfigFilepath() override;
|
||||
virtual void parseConfigKeyValue(QString key, QString value) override;
|
||||
virtual QMap<QString, QString> getKeyValueMap() override;
|
||||
virtual void init() override;
|
||||
virtual void setUnreadKeys() override;
|
||||
#ifdef CONFIG_BACKWARDS_COMPATABILITY
|
||||
friend class ProjectConfig;
|
||||
#endif
|
||||
|
||||
private:
|
||||
QStringList readKeys;
|
||||
QMap<QString, bool> customScripts;
|
||||
};
|
||||
|
||||
extern UserConfig userConfig;
|
||||
|
@ -571,7 +465,7 @@ protected:
|
|||
virtual QString getConfigFilepath() override;
|
||||
virtual void parseConfigKeyValue(QString key, QString value) override;
|
||||
virtual QMap<QString, QString> getKeyValueMap() override;
|
||||
virtual void onNewConfigFileCreated() override { };
|
||||
virtual void init() override { };
|
||||
virtual void setUnreadKeys() override { };
|
||||
|
||||
private:
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
#define EDITCOMMANDS_H
|
||||
|
||||
#include "blockdata.h"
|
||||
#include "mapconnection.h"
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include <QList>
|
||||
#include <QPointer>
|
||||
|
||||
class Map;
|
||||
class Layout;
|
||||
|
@ -31,6 +33,11 @@ enum CommandId {
|
|||
ID_EventDelete,
|
||||
ID_EventDuplicate,
|
||||
ID_EventPaste,
|
||||
ID_MapConnectionMove,
|
||||
ID_MapConnectionChangeDirection,
|
||||
ID_MapConnectionChangeMap,
|
||||
ID_MapConnectionAdd,
|
||||
ID_MapConnectionRemove,
|
||||
};
|
||||
|
||||
#define IDMask_EventType_Object (1 << 8)
|
||||
|
@ -379,4 +386,113 @@ private:
|
|||
int newBorderHeight;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit Map Connectien move actions.
|
||||
/// Actions are merged into one until the mouse is released when editing by click-and-drag,
|
||||
/// or when the offset spin box loses focus when editing with the list UI.
|
||||
class MapConnectionMove : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionMove(MapConnection *connection, int newOffset, unsigned actionId,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
bool mergeWith(const QUndoCommand *command) override;
|
||||
int id() const override { return CommandId::ID_MapConnectionMove; }
|
||||
|
||||
private:
|
||||
MapConnection *connection;
|
||||
int newOffset;
|
||||
int oldOffset;
|
||||
bool mirrored;
|
||||
unsigned actionId;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit changes to a Map Connectien's 'direction' field.
|
||||
class MapConnectionChangeDirection : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionChangeDirection(MapConnection *connection, QString newDirection,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return CommandId::ID_MapConnectionChangeDirection; }
|
||||
|
||||
private:
|
||||
QPointer<MapConnection> connection;
|
||||
QString newDirection;
|
||||
QString oldDirection;
|
||||
int oldOffset;
|
||||
int newOffset;
|
||||
bool mirrored;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit changes to a Map Connectien's 'map' field.
|
||||
class MapConnectionChangeMap : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionChangeMap(MapConnection *connection, QString newMapName,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return CommandId::ID_MapConnectionChangeMap; }
|
||||
|
||||
private:
|
||||
QPointer<MapConnection> connection;
|
||||
QString newMapName;
|
||||
QString oldMapName;
|
||||
int oldOffset;
|
||||
int newOffset;
|
||||
bool mirrored;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit adding a Map Connection to a map.
|
||||
class MapConnectionAdd : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionAdd(Map *map, MapConnection *connection,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return CommandId::ID_MapConnectionAdd; }
|
||||
|
||||
private:
|
||||
Map *map = nullptr;
|
||||
Map *mirrorMap = nullptr;
|
||||
QPointer<MapConnection> connection = nullptr;
|
||||
QPointer<MapConnection> mirror = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Implements a command to commit removing a Map Connection from a map.
|
||||
class MapConnectionRemove : public QUndoCommand {
|
||||
public:
|
||||
MapConnectionRemove(Map *map, MapConnection *connection,
|
||||
QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return CommandId::ID_MapConnectionRemove; }
|
||||
|
||||
private:
|
||||
Map *map = nullptr;
|
||||
Map *mirrorMap = nullptr;
|
||||
QPointer<MapConnection> connection = nullptr;
|
||||
QPointer<MapConnection> mirror = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif // EDITCOMMANDS_H
|
||||
|
|
|
@ -118,6 +118,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
static Event* create(Event::Type type);
|
||||
|
||||
static QMap<Event::Group, const QPixmap*> icons;
|
||||
|
||||
// standard public methods
|
||||
|
|
|
@ -72,8 +72,6 @@ public:
|
|||
QMap<Event::Group, QList<Event *>> events;
|
||||
QList<Event *> ownedEvents; // for memory management
|
||||
|
||||
QList<MapConnection*> connections;
|
||||
|
||||
QList<int> metatileLayerOrder;
|
||||
QList<float> metatileLayerOpacity;
|
||||
|
||||
|
@ -92,21 +90,34 @@ public:
|
|||
void removeEvent(Event *);
|
||||
void addEvent(Event *);
|
||||
|
||||
void deleteConnections();
|
||||
QList<MapConnection*> getConnections() const;
|
||||
void removeConnection(MapConnection *);
|
||||
void addConnection(MapConnection *);
|
||||
void loadConnection(MapConnection *);
|
||||
QRect getConnectionRect(const QString &direction, Layout *fromLayout = nullptr);
|
||||
QPixmap renderConnection(const QString &direction, Layout *fromLayout = nullptr);
|
||||
|
||||
QUndoStack editHistory;
|
||||
void modify();
|
||||
void clean();
|
||||
bool hasUnsavedChanges();
|
||||
void pruneEditHistory();
|
||||
|
||||
QPixmap renderConnection(MapConnection, Layout *);
|
||||
|
||||
private:
|
||||
void trackConnection(MapConnection*);
|
||||
|
||||
// MapConnections in 'ownedConnections' but not 'connections' persist in the edit history.
|
||||
QList<MapConnection*> connections;
|
||||
QSet<MapConnection*> ownedConnections;
|
||||
|
||||
signals:
|
||||
void mapChanged(Map *map);
|
||||
void modified();
|
||||
void mapDimensionsChanged(const QSize &size);
|
||||
void mapNeedsRedrawing();
|
||||
void openScriptRequested(QString label);
|
||||
void connectionAdded(MapConnection*);
|
||||
void connectionRemoved(MapConnection*);
|
||||
};
|
||||
|
||||
#endif // MAP_H
|
||||
|
|
|
@ -3,21 +3,61 @@
|
|||
#define MAPCONNECTION_H
|
||||
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
|
||||
class MapConnection {
|
||||
class Project;
|
||||
class Map;
|
||||
|
||||
class MapConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QString direction;
|
||||
int offset;
|
||||
QString map_name;
|
||||
MapConnection(const QString &targetMapName, const QString &direction, int offset = 0);
|
||||
|
||||
Map* parentMap() const { return m_parentMap; }
|
||||
QString parentMapName() const;
|
||||
void setParentMap(Map* map, bool mirror = true);
|
||||
|
||||
Map* targetMap() const;
|
||||
QString targetMapName() const { return m_targetMapName; }
|
||||
void setTargetMapName(const QString &targetMapName, bool mirror = true);
|
||||
|
||||
QString direction() const { return m_direction; }
|
||||
void setDirection(const QString &direction, bool mirror = true);
|
||||
|
||||
int offset() const { return m_offset; }
|
||||
void setOffset(int offset, bool mirror = true);
|
||||
|
||||
MapConnection* findMirror();
|
||||
MapConnection* createMirror();
|
||||
|
||||
QPixmap getPixmap();
|
||||
|
||||
static QPointer<Project> project;
|
||||
static const QMap<QString, QString> oppositeDirections;
|
||||
static const QStringList cardinalDirections;
|
||||
static bool isCardinal(const QString &direction);
|
||||
static bool isHorizontal(const QString &direction);
|
||||
static bool isVertical(const QString &direction);
|
||||
static bool isDiving(const QString &direction);
|
||||
static QString oppositeDirection(const QString &direction) { return oppositeDirections.value(direction, direction); }
|
||||
static bool areMirrored(const MapConnection*, const MapConnection*);
|
||||
|
||||
private:
|
||||
Map* m_parentMap;
|
||||
QString m_targetMapName;
|
||||
QString m_direction;
|
||||
int m_offset;
|
||||
|
||||
void markMapEdited();
|
||||
Map* getMap(const QString& mapName) const;
|
||||
|
||||
signals:
|
||||
void parentMapChanged(Map* before, Map* after);
|
||||
void targetMapNameChanged(QString before, QString after);
|
||||
void directionChanged(QString before, QString after);
|
||||
void offsetChanged(int before, int after);
|
||||
};
|
||||
|
||||
inline bool operator==(const MapConnection &c1, const MapConnection &c2) {
|
||||
return c1.map_name == c2.map_name;
|
||||
}
|
||||
|
||||
inline uint qHash(const MapConnection &key) {
|
||||
return qHash(key.map_name);
|
||||
}
|
||||
|
||||
#endif // MAPCONNECTION_H
|
||||
|
|
|
@ -22,9 +22,9 @@ struct WildPokemonHeader {
|
|||
};
|
||||
|
||||
struct EncounterField {
|
||||
QString name;
|
||||
QString name; // Ex: "fishing_mons"
|
||||
QVector<int> encounterRates;
|
||||
tsl::ordered_map<QString, QVector<int>> groups;
|
||||
tsl::ordered_map<QString, QVector<int>> groups; // Ex: "good_rod", {2, 3, 4}
|
||||
};
|
||||
|
||||
typedef QVector<EncounterField> EncounterFields;
|
||||
|
|
104
include/editor.h
104
include/editor.h
|
@ -19,6 +19,7 @@
|
|||
#include "ui_mainwindow.h"
|
||||
#include "bordermetatilespixmapitem.h"
|
||||
#include "connectionpixmapitem.h"
|
||||
#include "divingmappixmapitem.h"
|
||||
#include "currentselectedmetatilespixmapitem.h"
|
||||
#include "collisionpixmapitem.h"
|
||||
#include "layoutpixmapitem.h"
|
||||
|
@ -26,6 +27,7 @@
|
|||
#include "movablerect.h"
|
||||
#include "cursortilerect.h"
|
||||
#include "mapruler.h"
|
||||
#include "encountertablemodel.h"
|
||||
|
||||
class DraggablePixmapItem;
|
||||
class MetatilesPixmapItem;
|
||||
|
@ -45,7 +47,7 @@ public:
|
|||
Ui::MainWindow* ui;
|
||||
QObject *parent = nullptr;
|
||||
|
||||
Project *project = nullptr;
|
||||
QPointer<Project> project = nullptr;
|
||||
QPointer<Map> map = nullptr;
|
||||
QPointer<Layout> layout = nullptr;
|
||||
|
||||
|
@ -53,6 +55,7 @@ public:
|
|||
|
||||
Settings *settings;
|
||||
|
||||
void setProject(Project * project);
|
||||
void save();
|
||||
void saveProject();
|
||||
void saveUiFields();
|
||||
|
@ -85,20 +88,19 @@ public:
|
|||
void updateMapBorder();
|
||||
void updateMapConnections();
|
||||
|
||||
void setCurrentConnectionDirection(QString curDirection);
|
||||
void updateCurrentConnectionDirection(QString curDirection);
|
||||
void setConnectionsVisibility(bool visible);
|
||||
void updateConnectionOffset(int offset);
|
||||
void setConnectionMap(QString mapName);
|
||||
void addNewConnection();
|
||||
void removeCurrentConnection();
|
||||
void updateDiveMap(QString mapName);
|
||||
void updateEmergeMap(QString mapName);
|
||||
void setSelectedConnectionFromMap(QString mapName);
|
||||
|
||||
void updateDivingMapsVisibility();
|
||||
void renderDivingConnections();
|
||||
void addConnection(MapConnection* connection);
|
||||
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);
|
||||
void setSelectedConnection(MapConnection *connection);
|
||||
|
||||
void updatePrimaryTileset(QString tilesetLabel, bool forceLoad = false);
|
||||
void updateSecondaryTileset(QString tilesetLabel, bool forceLoad = false);
|
||||
|
@ -107,8 +109,7 @@ public:
|
|||
|
||||
DraggablePixmapItem *addMapEvent(Event *event);
|
||||
bool eventLimitReached(Map *, Event::Type);
|
||||
void selectMapEvent(DraggablePixmapItem *object);
|
||||
void selectMapEvent(DraggablePixmapItem *object, bool toggle);
|
||||
void selectMapEvent(DraggablePixmapItem *object, bool toggle = false);
|
||||
DraggablePixmapItem *addNewEvent(Event::Type type);
|
||||
void updateSelectedEvents();
|
||||
void duplicateSelectedEvents();
|
||||
|
@ -121,13 +122,13 @@ public:
|
|||
void updateWarpEventWarning(Event *event);
|
||||
void updateWarpEventWarnings();
|
||||
|
||||
QGraphicsScene *scene = nullptr;
|
||||
QPointer<QGraphicsScene> scene = nullptr;
|
||||
QGraphicsPixmapItem *current_view = nullptr;
|
||||
LayoutPixmapItem *map_item = nullptr;
|
||||
ConnectionPixmapItem* selected_connection_item = nullptr;
|
||||
QList<ConnectionPixmapItem*> connection_items;
|
||||
QPointer<LayoutPixmapItem> map_item = nullptr;
|
||||
QList<QPointer<ConnectionPixmapItem>> connection_items;
|
||||
QMap<QString, QPointer<DivingMapPixmapItem>> diving_map_items;
|
||||
QGraphicsPathItem *connection_mask = nullptr;
|
||||
CollisionPixmapItem *collision_item = nullptr;
|
||||
QPointer<CollisionPixmapItem> collision_item = nullptr;
|
||||
QGraphicsItemGroup *events_group = nullptr;
|
||||
|
||||
QList<QGraphicsPixmapItem*> borderItems;
|
||||
|
@ -137,19 +138,19 @@ public:
|
|||
MovableRect *playerViewRect = nullptr;
|
||||
CursorTileRect *cursorMapTileRect = nullptr;
|
||||
|
||||
QGraphicsScene *scene_metatiles = nullptr;
|
||||
QGraphicsScene *scene_current_metatile_selection = nullptr;
|
||||
QGraphicsScene *scene_selected_border_metatiles = nullptr;
|
||||
QGraphicsScene *scene_collision_metatiles = nullptr;
|
||||
QGraphicsScene *scene_elevation_metatiles = nullptr;
|
||||
QPointer<QGraphicsScene> scene_metatiles = nullptr;
|
||||
QPointer<QGraphicsScene> scene_current_metatile_selection = nullptr;
|
||||
QPointer<QGraphicsScene> scene_selected_border_metatiles = nullptr;
|
||||
QPointer<QGraphicsScene> scene_collision_metatiles = nullptr;
|
||||
QPointer<MetatileSelector> metatile_selector_item = nullptr;
|
||||
|
||||
MetatileSelector *metatile_selector_item = nullptr;
|
||||
|
||||
BorderMetatilesPixmapItem *selected_border_metatiles_item = nullptr;
|
||||
QPointer<BorderMetatilesPixmapItem> selected_border_metatiles_item = nullptr;
|
||||
CurrentSelectedMetatilesPixmapItem *current_metatile_selection_item = nullptr;
|
||||
MovementPermissionsSelector *movement_permissions_selector_item = nullptr;
|
||||
QPointer<MovementPermissionsSelector> movement_permissions_selector_item = nullptr;
|
||||
|
||||
QList<DraggablePixmapItem *> *selected_events = nullptr;
|
||||
QPointer<ConnectionPixmapItem> selected_connection_item = nullptr;
|
||||
QPointer<MapConnection> connection_to_select = nullptr;
|
||||
|
||||
enum class EditAction { None, Paint, Select, Fill, Shift, Pick, Move };
|
||||
EditAction mapEditAction = EditAction::Paint;
|
||||
|
@ -202,21 +203,28 @@ private:
|
|||
const QImage collisionPlaceholder = QImage(":/images/collisions_unknown.png");
|
||||
QPixmap collisionSheetPixmap;
|
||||
|
||||
void setConnectionItemsVisible(bool);
|
||||
void setBorderItemsVisible(bool, qreal = 1);
|
||||
void setConnectionEditControlValues(MapConnection*);
|
||||
void setConnectionEditControlsEnabled(bool);
|
||||
void setConnectionsEditable(bool);
|
||||
void createConnectionItem(MapConnection* connection);
|
||||
void populateConnectionMapPickers();
|
||||
void setDiveEmergeControls();
|
||||
void updateDiveEmergeMap(QString mapName, QString direction);
|
||||
void onConnectionOffsetChanged(int newOffset);
|
||||
void removeMirroredConnection(MapConnection*);
|
||||
void updateMirroredConnectionOffset(MapConnection*);
|
||||
void updateMirroredConnectionDirection(MapConnection*, QString);
|
||||
void updateMirroredConnectionMap(MapConnection*, QString);
|
||||
void updateMirroredConnection(MapConnection*, QString, QString, bool isDelete = false);
|
||||
void clearMap();
|
||||
void clearMetatileSelector();
|
||||
void clearMovementPermissionSelector();
|
||||
void clearMapMetatiles();
|
||||
void clearMapMovementPermissions();
|
||||
void clearBorderMetatiles();
|
||||
void clearCurrentMetatilesSelection();
|
||||
void clearMapEvents();
|
||||
void clearMapConnections();
|
||||
void clearConnectionMask();
|
||||
void clearMapBorder();
|
||||
void clearMapGrid();
|
||||
void clearWildMonTables();
|
||||
void updateBorderVisibility();
|
||||
void disconnectMapConnection(MapConnection *connection);
|
||||
QPoint getConnectionOrigin(MapConnection *connection);
|
||||
void removeConnectionPixmap(MapConnection *connection);
|
||||
void updateConnectionPixmap(ConnectionPixmapItem *connectionItem);
|
||||
void displayConnection(MapConnection *connection);
|
||||
void displayDivingConnection(MapConnection *connection);
|
||||
void setDivingMapName(QString mapName, QString direction);
|
||||
void removeDivingMapPixmap(MapConnection *connection);
|
||||
void updateEncounterFields(EncounterFields newFields);
|
||||
QString getMovementPermissionText(uint16_t collision, uint16_t elevation);
|
||||
QString getMetatileDisplayMessage(uint16_t metatileId);
|
||||
|
@ -232,10 +240,7 @@ private slots:
|
|||
void setStraightPathCursorMode(QGraphicsSceneMouseEvent *event);
|
||||
void mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *item);
|
||||
void mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item);
|
||||
void onConnectionMoved(MapConnection*);
|
||||
void onConnectionItemSelected(ConnectionPixmapItem* connectionItem);
|
||||
void onConnectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
|
||||
void onConnectionDirectionChanged(QString newDirection);
|
||||
void setSelectedConnectionItem(ConnectionPixmapItem *connectionItem);
|
||||
void onHoveredMovementPermissionChanged(uint16_t, uint16_t);
|
||||
void onHoveredMovementPermissionCleared();
|
||||
void onHoveredMetatileSelectionChanged(uint16_t);
|
||||
|
@ -250,12 +255,13 @@ private slots:
|
|||
|
||||
signals:
|
||||
void objectsChanged();
|
||||
void loadMapRequested(QString, QString);
|
||||
void wildMonDataChanged();
|
||||
void openConnectedMap(MapConnection*);
|
||||
void wildMonTableOpened(EncounterTableModel*);
|
||||
void wildMonTableClosed();
|
||||
void wildMonTableEdited();
|
||||
void warpEventDoubleClicked(QString, int, Event::Group);
|
||||
void currentMetatilesSelectionChanged();
|
||||
void mapRulerStatusChanged(const QString &);
|
||||
void editedMapData();
|
||||
void tilesetUpdated(QString);
|
||||
};
|
||||
|
||||
|
|
|
@ -28,7 +28,9 @@
|
|||
#include "preferenceeditor.h"
|
||||
#include "projectsettingseditor.h"
|
||||
#include "customscriptseditor.h"
|
||||
#include "wildmonchart.h"
|
||||
#include "updatepromoter.h"
|
||||
#include "aboutporymap.h"
|
||||
|
||||
|
||||
|
||||
|
@ -168,6 +170,7 @@ public slots:
|
|||
private slots:
|
||||
void on_action_Open_Project_triggered();
|
||||
void on_action_Reload_Project_triggered();
|
||||
void on_action_Close_Project_triggered();
|
||||
|
||||
void on_mapList_activated(const QModelIndex &index);
|
||||
void on_areaList_activated(const QModelIndex &index);
|
||||
|
@ -183,18 +186,19 @@ private slots:
|
|||
void copy();
|
||||
void paste();
|
||||
|
||||
void onLoadMapRequested(QString, QString);
|
||||
void onMapChanged(Map *map);
|
||||
void onLayoutChanged(Layout *layout);
|
||||
void onOpenConnectedMap(MapConnection*);
|
||||
void onMapNeedsRedrawing();
|
||||
void onLayoutNeedsRedrawing();
|
||||
void onTilesetsSaved(QString, QString);
|
||||
void onWildMonDataChanged();
|
||||
void openNewMapPopupWindow();
|
||||
void onNewMapCreated();
|
||||
void onMapLoaded(Map *map);
|
||||
void importMapFromAdvanceMap1_92();
|
||||
void onMapRulerStatusChanged(const QString &);
|
||||
void applyUserShortcuts();
|
||||
void markMapEdited();
|
||||
void markSpecificMapEdited(Map*);
|
||||
|
||||
void on_action_NewMap_triggered();
|
||||
void on_actionNew_Tileset_triggered();
|
||||
|
@ -225,10 +229,11 @@ private slots:
|
|||
void on_actionMove_triggered();
|
||||
void on_actionMap_Shift_triggered();
|
||||
|
||||
void onDeleteKeyPressed();
|
||||
void on_toolButton_deleteObject_clicked();
|
||||
|
||||
void addNewEvent(Event::Type type);
|
||||
void tryAddEventTab(QWidget * tab, Event::Group group);
|
||||
void tryAddEventTab(QWidget * tab);
|
||||
void displayEventTabs();
|
||||
void updateSelectedObjects();
|
||||
void updateObjects();
|
||||
|
@ -252,11 +257,9 @@ private slots:
|
|||
void on_actionExport_Map_Timelapse_Image_triggered();
|
||||
void on_actionImport_Map_from_Advance_Map_1_92_triggered();
|
||||
|
||||
void on_comboBox_ConnectionDirection_currentTextChanged(const QString &arg1);
|
||||
void on_spinBox_ConnectionOffset_valueChanged(int offset);
|
||||
void on_comboBox_ConnectedMap_currentTextChanged(const QString &mapName);
|
||||
void on_pushButton_AddConnection_clicked();
|
||||
void on_pushButton_RemoveConnection_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);
|
||||
|
@ -279,6 +282,12 @@ private slots:
|
|||
|
||||
void eventTabChanged(int index);
|
||||
|
||||
void on_checkBox_MirrorConnections_stateChanged(int selected);
|
||||
void on_actionDive_Emerge_Map_triggered();
|
||||
void on_groupBox_DiveMapOpacity_toggled(bool on);
|
||||
void on_slider_DiveEmergeMapOpacity_valueChanged(int value);
|
||||
void on_slider_DiveMapOpacity_valueChanged(int value);
|
||||
void on_slider_EmergeMapOpacity_valueChanged(int value);
|
||||
void on_horizontalSlider_CollisionTransparency_valueChanged(int value);
|
||||
|
||||
void do_HideShow();
|
||||
|
@ -305,6 +314,7 @@ private slots:
|
|||
void on_horizontalSlider_CollisionZoom_valueChanged(int value);
|
||||
void on_pushButton_NewWildMonGroup_clicked();
|
||||
void on_pushButton_DeleteWildMonGroup_clicked();
|
||||
void on_pushButton_SummaryChart_clicked();
|
||||
void on_pushButton_ConfigureEncountersJSON_clicked();
|
||||
void on_pushButton_CreatePrefab_clicked();
|
||||
void on_spinBox_SelectedElevation_valueChanged(int elevation);
|
||||
|
@ -319,7 +329,7 @@ private slots:
|
|||
|
||||
public:
|
||||
Ui::MainWindow *ui;
|
||||
Editor *editor = nullptr;
|
||||
QPointer<Editor> editor = nullptr;
|
||||
|
||||
private:
|
||||
QLabel *label_MapRulerStatus = nullptr;
|
||||
|
@ -343,6 +353,8 @@ private:
|
|||
|
||||
QPointer<UpdatePromoter> updatePromoter = nullptr;
|
||||
QPointer<NetworkAccessManager> networkAccessManager = nullptr;
|
||||
QPointer<AboutPorymap> aboutWindow = nullptr;
|
||||
QPointer<WildMonChart> wildMonChart = nullptr;
|
||||
|
||||
QAction *undoAction = nullptr;
|
||||
QAction *redoAction = nullptr;
|
||||
|
@ -350,22 +362,11 @@ private:
|
|||
QAction *copyAction = nullptr;
|
||||
QAction *pasteAction = nullptr;
|
||||
|
||||
QWidget *eventTabObjectWidget;
|
||||
QWidget *eventTabWarpWidget;
|
||||
QWidget *eventTabTriggerWidget;
|
||||
QWidget *eventTabBGWidget;
|
||||
QWidget *eventTabHealspotWidget;
|
||||
QWidget *eventTabMultipleWidget;
|
||||
QMap<Event::Group, DraggablePixmapItem*> lastSelectedEvent;
|
||||
|
||||
bool isProgrammaticEventTabChange;
|
||||
bool projectHasUnsavedChanges;
|
||||
bool projectOpenFailure = false;
|
||||
bool newMapDefaultsSet = false;
|
||||
|
||||
MapSortOrder mapSortOrder;
|
||||
enum MapListTab { Groups = 0, Areas, Layouts };
|
||||
|
||||
bool tilesetNeedsRedraw = false;
|
||||
|
||||
bool setDefaultView();
|
||||
|
@ -373,26 +374,34 @@ private:
|
|||
bool setLayout(QString layoutId);
|
||||
bool setMap(QString, bool scroll = false);
|
||||
void unsetMap();
|
||||
|
||||
bool userSetMap(QString, bool scrollTreeView = false);
|
||||
void redrawMapScene();
|
||||
void redrawLayoutScene();
|
||||
void refreshMapScene();
|
||||
bool loadDataStructures();
|
||||
bool loadProjectCombos();
|
||||
bool populateMapList();
|
||||
|
||||
bool checkProjectSanity();
|
||||
bool loadProjectData();
|
||||
bool setProjectUI();
|
||||
void clearProjectUI();
|
||||
|
||||
void openSubWindow(QWidget * window);
|
||||
void scrollTreeView(QString itemName);
|
||||
QString getExistingDirectory(QString);
|
||||
bool openProject(const QString &dir, bool initial = false);
|
||||
bool openProject(QString dir, bool initial = false);
|
||||
bool closeProject();
|
||||
void showProjectOpenFailure();
|
||||
QString getDefaultMap();
|
||||
QString getDefaultLayout();
|
||||
void setRecentMapConfig(QString map_name);
|
||||
void setRecentLayoutConfig(QString layoutId);
|
||||
|
||||
QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum);
|
||||
|
||||
bool setInitialMap();
|
||||
bool setInitialLayout();
|
||||
void setRecentMap(QString map_name);
|
||||
QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum);
|
||||
QString getDefaultMap();
|
||||
QString getDefaultLayout();
|
||||
|
||||
void setRecentMapConfig(QString map_name);
|
||||
void setRecentLayoutConfig(QString layoutId);
|
||||
void saveGlobalConfigs();
|
||||
|
||||
void refreshRecentProjectsMenu();
|
||||
|
||||
void updateMapList();
|
||||
|
@ -409,7 +418,6 @@ private:
|
|||
void checkToolButtons();
|
||||
void clickToolButtonFromEditAction(Editor::EditAction editAction);
|
||||
|
||||
void markMapEdited();
|
||||
void showWindowTitle();
|
||||
|
||||
void initWindow();
|
||||
|
@ -420,18 +428,18 @@ private:
|
|||
void initMapSortOrder();
|
||||
void initShortcuts();
|
||||
void initExtraShortcuts();
|
||||
void setProjectSpecificUI();
|
||||
void loadUserSettings();
|
||||
void applyMapListFilter(QString filterText);
|
||||
void restoreWindowState();
|
||||
void setTheme(QString);
|
||||
void updateTilesetEditor();
|
||||
Event::Group getEventGroupFromTabWidget(QWidget *tab);
|
||||
void closeSupplementaryWindows();
|
||||
bool closeSupplementaryWindows();
|
||||
void setWindowDisabled(bool);
|
||||
|
||||
void initTilesetEditor();
|
||||
bool initRegionMapEditor(bool silent = false);
|
||||
bool askToFixRegionMapEditor();
|
||||
void initShortcutsEditor();
|
||||
void initCustomScriptsEditor();
|
||||
void connectSubEditorsToShortcutsEditor();
|
||||
|
@ -447,6 +455,32 @@ private:
|
|||
int insertTilesetLabel(QStringList * list, QString label);
|
||||
|
||||
void checkForUpdates(bool requestedByUser);
|
||||
void setDivingMapsVisible(bool visible);
|
||||
};
|
||||
|
||||
// These are namespaced in a struct to avoid colliding with e.g. class Map.
|
||||
struct MainTab {
|
||||
enum {
|
||||
Map,
|
||||
Events,
|
||||
Header,
|
||||
Connections,
|
||||
WildPokemon,
|
||||
};
|
||||
};
|
||||
|
||||
struct MapViewTab {
|
||||
enum {
|
||||
Metatiles,
|
||||
Collision,
|
||||
Prefabs,
|
||||
};
|
||||
};
|
||||
|
||||
struct MapListTab {
|
||||
enum {
|
||||
Groups = 0, Areas, Layouts
|
||||
};
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
@ -39,7 +39,6 @@ public:
|
|||
QMap<QString, int> mapGroups;
|
||||
QList<QStringList> groupedMapNames;
|
||||
QStringList mapNames;
|
||||
QMap<QString, QVariant> miscConstants;
|
||||
QList<HealLocation> healLocations;
|
||||
QMap<QString, int> healLocationNameToValue;
|
||||
QMap<QString, QString> mapConstantsToMapNames;
|
||||
|
@ -80,6 +79,9 @@ public:
|
|||
bool usingAsmTilesets;
|
||||
QString importExportPath;
|
||||
QSet<QString> disabledSettingsNames;
|
||||
int pokemonMinLevel;
|
||||
int pokemonMaxLevel;
|
||||
int maxEncounterRate;
|
||||
bool wildEncountersLoaded;
|
||||
|
||||
// For files that are read and could contain extra text
|
||||
|
@ -102,6 +104,9 @@ public:
|
|||
DataQualifiers healLocationDataQualifiers;
|
||||
QString healLocationsTableName;
|
||||
|
||||
bool sanityCheck();
|
||||
bool load();
|
||||
|
||||
QMap<QString, Map*> mapCache;
|
||||
Map* loadMap(QString);
|
||||
Map* getMap(QString);
|
||||
|
@ -164,6 +169,7 @@ public:
|
|||
void saveAllMaps();
|
||||
void saveMap(Map *);
|
||||
void saveAllDataStructures();
|
||||
void saveConfig();
|
||||
void saveMapLayouts();
|
||||
void saveMapGroups();
|
||||
void saveMapSections();
|
||||
|
@ -264,6 +270,7 @@ private:
|
|||
signals:
|
||||
void reloadProject();
|
||||
void uncheckMonitorFilesAction();
|
||||
void mapLoaded(Map *map);
|
||||
};
|
||||
|
||||
#endif // PROJECT_H
|
||||
|
|
|
@ -30,7 +30,9 @@ class Scripting
|
|||
{
|
||||
public:
|
||||
Scripting(MainWindow *mainWindow);
|
||||
~Scripting();
|
||||
static void init(MainWindow *mainWindow);
|
||||
static void stop();
|
||||
static void populateGlobalObject(MainWindow *mainWindow);
|
||||
static QJSEngine *getEngine();
|
||||
static void invokeAction(int actionIndex);
|
||||
|
|
|
@ -10,7 +10,8 @@ class ScriptUtility : public QObject
|
|||
|
||||
public:
|
||||
ScriptUtility(MainWindow *mainWindow);
|
||||
void clearActions();
|
||||
~ScriptUtility();
|
||||
|
||||
QString getActionFunctionName(int actionIndex);
|
||||
Q_INVOKABLE bool registerAction(QString functionName, QString actionName, QString shortcut = "");
|
||||
Q_INVOKABLE bool registerToggleAction(QString functionName, QString actionName, QString shortcut = "", bool checked = false);
|
||||
|
@ -59,6 +60,7 @@ private:
|
|||
|
||||
MainWindow *window;
|
||||
QList<QAction *> registeredActions;
|
||||
QSet<QTimer *> activeTimers;
|
||||
QHash<int, QString> actionMap;
|
||||
};
|
||||
|
||||
|
|
|
@ -4,44 +4,46 @@
|
|||
#include "mapconnection.h"
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QPainter>
|
||||
#include <QPointer>
|
||||
|
||||
class ConnectionPixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConnectionPixmapItem(QPixmap pixmap, MapConnection* connection, int x, int y, int baseMapWidth, int baseMapHeight): QGraphicsPixmapItem(pixmap) {
|
||||
this->basePixmap = pixmap;
|
||||
this->connection = connection;
|
||||
setFlag(ItemIsMovable);
|
||||
setFlag(ItemSendsGeometryChanges);
|
||||
this->initialX = x;
|
||||
this->initialY = y;
|
||||
this->initialOffset = connection->offset;
|
||||
this->baseMapWidth = baseMapWidth;
|
||||
this->baseMapHeight = baseMapHeight;
|
||||
}
|
||||
QPixmap basePixmap;
|
||||
MapConnection* connection;
|
||||
int initialX;
|
||||
int initialY;
|
||||
int initialOffset;
|
||||
int baseMapWidth;
|
||||
int baseMapHeight;
|
||||
void render(qreal opacity = 1);
|
||||
int getMinOffset();
|
||||
int getMaxOffset();
|
||||
ConnectionPixmapItem(MapConnection* connection, int originX, int originY);
|
||||
ConnectionPixmapItem(MapConnection* connection, QPoint origin);
|
||||
|
||||
const QPointer<MapConnection> connection;
|
||||
|
||||
void setOrigin(int x, int y);
|
||||
void setOrigin(QPoint pos);
|
||||
|
||||
void setEditable(bool editable);
|
||||
bool getEditable();
|
||||
void updateHighlight(bool selected);
|
||||
|
||||
void setSelected(bool selected);
|
||||
|
||||
void updatePos();
|
||||
void render(bool ignoreCache = false);
|
||||
|
||||
private:
|
||||
QPixmap basePixmap;
|
||||
qreal originX;
|
||||
qreal originY;
|
||||
bool selected = false;
|
||||
unsigned actionId = 0;
|
||||
|
||||
static const int mWidth = 16;
|
||||
static const int mHeight = 16;
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*);
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*);
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override;
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*) override;
|
||||
|
||||
signals:
|
||||
void connectionItemSelected(ConnectionPixmapItem* connectionItem);
|
||||
void connectionItemDoubleClicked(ConnectionPixmapItem* connectionItem);
|
||||
void connectionMoved(MapConnection*);
|
||||
void connectionItemDoubleClicked(MapConnection*);
|
||||
void selectionChanged(bool selected);
|
||||
};
|
||||
|
||||
#endif // CONNECTIONPIXMAPITEM_H
|
||||
|
|
52
include/ui/connectionslistitem.h
Normal file
52
include/ui/connectionslistitem.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef CONNECTIONSLISTITEM_H
|
||||
#define CONNECTIONSLISTITEM_H
|
||||
|
||||
#include "mapconnection.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <QFrame>
|
||||
#include <QMouseEvent>
|
||||
#include <QPointer>
|
||||
|
||||
namespace Ui {
|
||||
class ConnectionsListItem;
|
||||
}
|
||||
|
||||
// We show the data for each map connection in the panel on the right side of the Connections tab.
|
||||
// An instance of this class is used for each item in that list.
|
||||
// It communicates with the ConnectionPixmapItem on the map through a shared MapConnection pointer.
|
||||
class ConnectionsListItem : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConnectionsListItem(QWidget *parent, MapConnection *connection, const QStringList &mapNames);
|
||||
~ConnectionsListItem();
|
||||
|
||||
void updateUI();
|
||||
void setSelected(bool selected);
|
||||
|
||||
private:
|
||||
Ui::ConnectionsListItem *ui;
|
||||
QPointer<MapConnection> connection;
|
||||
Map *map;
|
||||
bool isSelected = false;
|
||||
unsigned actionId = 0;
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent*) override;
|
||||
|
||||
signals:
|
||||
void selected();
|
||||
void removed(MapConnection*);
|
||||
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();
|
||||
};
|
||||
|
||||
#endif // CONNECTIONSLISTITEM_H
|
|
@ -55,7 +55,8 @@ private slots:
|
|||
void dialogButtonClicked(QAbstractButton *button);
|
||||
void createNewScript();
|
||||
void loadScript();
|
||||
void refreshScripts();
|
||||
bool refreshScripts();
|
||||
void userRefreshScripts();
|
||||
void removeSelectedScripts();
|
||||
void openSelectedScripts();
|
||||
};
|
||||
|
|
30
include/ui/divingmappixmapitem.h
Normal file
30
include/ui/divingmappixmapitem.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef DIVINGMAPPIXMAPITEM_H
|
||||
#define DIVINGMAPPIXMAPITEM_H
|
||||
|
||||
#include "mapconnection.h"
|
||||
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QPointer>
|
||||
#include <QComboBox>
|
||||
|
||||
class DivingMapPixmapItem : public QObject, public QGraphicsPixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DivingMapPixmapItem(MapConnection *connection, QComboBox *combo);
|
||||
~DivingMapPixmapItem();
|
||||
|
||||
MapConnection* connection() const { return m_connection; }
|
||||
void updatePixmap();
|
||||
|
||||
private:
|
||||
QPointer<MapConnection> m_connection;
|
||||
QPointer<QComboBox> m_combo;
|
||||
|
||||
void setComboText(const QString &text);
|
||||
static QPixmap getBasePixmap(MapConnection* connection);
|
||||
|
||||
private slots:
|
||||
void onTargetMapChanged();
|
||||
};
|
||||
|
||||
#endif // DIVINGMAPPIXMAPITEM_H
|
|
@ -24,13 +24,7 @@ public:
|
|||
updatePosition();
|
||||
}
|
||||
|
||||
Editor *editor = nullptr;
|
||||
Event *event = nullptr;
|
||||
QGraphicsItemAnimation *pos_anim = nullptr;
|
||||
|
||||
bool active;
|
||||
int last_x;
|
||||
int last_y;
|
||||
|
||||
void updatePosition();
|
||||
void move(int dx, int dy);
|
||||
|
@ -38,6 +32,12 @@ public:
|
|||
void emitPositionChanged();
|
||||
void updatePixmap();
|
||||
|
||||
private:
|
||||
Editor *editor = nullptr;
|
||||
QPoint lastPos;
|
||||
bool active = false;
|
||||
bool releaseSelectionQueued = false;
|
||||
|
||||
signals:
|
||||
void positionChanged(Event *event);
|
||||
void xChanged(int);
|
||||
|
|
|
@ -28,7 +28,9 @@ public:
|
|||
Slot, Group, Species, MinLevel, MaxLevel, EncounterChance, SlotRatio, EncounterRate, Count
|
||||
};
|
||||
|
||||
WildMonInfo encounterData();
|
||||
WildMonInfo encounterData() const { return this->monInfo; }
|
||||
EncounterField encounterField() const { return this->encounterFields.at(this->fieldIndex); }
|
||||
QList<double> percentages() const { return this->slotPercentages; }
|
||||
void resize(int rows, int cols);
|
||||
|
||||
private:
|
||||
|
|
|
@ -51,9 +51,10 @@ private:
|
|||
ImageExporterMode mode = ImageExporterMode::Normal;
|
||||
|
||||
void updatePreview();
|
||||
void updateShowBorderState();
|
||||
void saveImage();
|
||||
QPixmap getStitchedImage(QProgressDialog *progress, bool includeBorder);
|
||||
QPixmap getFormattedMapPixmap(Map *map, bool ignoreBorder);
|
||||
QPixmap getFormattedMapPixmap(Map *map, bool ignoreBorder = false);
|
||||
bool historyItemAppliesToFrame(const QUndoCommand *command);
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
class Project;
|
||||
|
||||
enum MapListRoles {
|
||||
enum MapListUserRoles {
|
||||
GroupRole = Qt::UserRole + 1, // Used to hold the map group number.
|
||||
TypeRole, // Used to differentiate between the different layers of the map list tree view.
|
||||
TypeRole2, // Used for various extra data needed.
|
||||
|
|
32
include/ui/newmapconnectiondialog.h
Normal file
32
include/ui/newmapconnectiondialog.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef NEWMAPCONNECTIONDIALOG_H
|
||||
#define NEWMAPCONNECTIONDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "map.h"
|
||||
#include "mapconnection.h"
|
||||
|
||||
namespace Ui {
|
||||
class NewMapConnectionDialog;
|
||||
}
|
||||
|
||||
class NewMapConnectionDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NewMapConnectionDialog(QWidget *parent, Map* map, const QStringList &mapNames);
|
||||
~NewMapConnectionDialog();
|
||||
|
||||
virtual void accept() override;
|
||||
|
||||
signals:
|
||||
void accepted(MapConnection *result);
|
||||
|
||||
private:
|
||||
Ui::NewMapConnectionDialog *ui;
|
||||
|
||||
bool mapNameIsValid();
|
||||
void setWarningVisible(bool visible);
|
||||
};
|
||||
|
||||
#endif // NEWMAPCONNECTIONDIALOG_H
|
|
@ -13,9 +13,15 @@ public:
|
|||
void setTextItem(const QString &text);
|
||||
void setNumberItem(int value);
|
||||
void setHexItem(uint32_t value);
|
||||
void setClearButtonEnabled(bool enabled);
|
||||
void setEditable(bool editable);
|
||||
void setLineEdit(QLineEdit *edit);
|
||||
void setFocusedScrollingEnabled(bool enabled);
|
||||
|
||||
private:
|
||||
void setItem(int index, const QString &text);
|
||||
|
||||
bool focusedScrollingEnabled = true;
|
||||
};
|
||||
|
||||
#endif // NOSCROLLCOMBOBOX_H
|
||||
|
|
|
@ -61,7 +61,7 @@ private:
|
|||
void chooseImageFile(QLineEdit * filepathEdit);
|
||||
void chooseFile(QLineEdit * filepathEdit, const QString &description, const QString &extensions);
|
||||
QString stripProjectDir(QString s);
|
||||
void disableParsedSetting(QWidget * widget, const QString &name, const QString &filepath);
|
||||
bool disableParsedSetting(QWidget * widget, const QString &identifier, const QString &filepath);
|
||||
void updateMaskOverlapWarning(QLabel * warning, QList<UIntSpinBox*> masks);
|
||||
QStringList getWarpBehaviorsList();
|
||||
void setWarpBehaviorsList(QStringList list);
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
~RegionMapEditor();
|
||||
|
||||
bool load(bool silent = false);
|
||||
bool setupErrored() const { return setupError; }
|
||||
|
||||
void onRegionMapTileSelectorSelectedTileChanged(unsigned id);
|
||||
void onRegionMapTileSelectorHoveredTileChanged(unsigned id);
|
||||
|
@ -41,6 +42,8 @@ public:
|
|||
|
||||
void resizeTilemap(int width, int height);
|
||||
|
||||
bool reconfigure();
|
||||
|
||||
QObjectList shortcutableObjects() const;
|
||||
|
||||
public slots:
|
||||
|
@ -53,9 +56,13 @@ private:
|
|||
RegionMap *region_map = nullptr;
|
||||
tsl::ordered_map<QString, RegionMap *> region_maps;
|
||||
|
||||
QString configFilepath;
|
||||
QString mapSectionFilepath;
|
||||
|
||||
poryjson::Json rmConfigJson;
|
||||
|
||||
bool configSaved = false;
|
||||
bool setupError = false;
|
||||
|
||||
QUndoGroup history;
|
||||
|
||||
|
|
98
include/ui/wildmonchart.h
Normal file
98
include/ui/wildmonchart.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
#ifndef WILDMONCHART_H
|
||||
#define WILDMONCHART_H
|
||||
|
||||
#include "encountertablemodel.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#if __has_include(<QtCharts>)
|
||||
#include <QtCharts>
|
||||
|
||||
namespace Ui {
|
||||
class WildMonChart;
|
||||
}
|
||||
|
||||
class WildMonChart : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WildMonChart(QWidget *parent, const EncounterTableModel *table);
|
||||
~WildMonChart();
|
||||
|
||||
virtual void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
public slots:
|
||||
void setTable(const EncounterTableModel *table);
|
||||
void clearTable();
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
Ui::WildMonChart *ui;
|
||||
const EncounterTableModel *table;
|
||||
|
||||
QStringList groupNames;
|
||||
QStringList groupNamesReversed;
|
||||
QStringList speciesInLegendOrder;
|
||||
QMap<int, QString> tableIndexToGroupName;
|
||||
|
||||
struct LevelRange {
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
QMap<QString, LevelRange> groupedLevelRanges;
|
||||
|
||||
struct Summary {
|
||||
double speciesFrequency = 0.0;
|
||||
QMap<int, double> levelFrequencies;
|
||||
};
|
||||
typedef QMap<QString, Summary> GroupedData;
|
||||
|
||||
QMap<QString, GroupedData> speciesToGroupedData;
|
||||
QMap<QString, QColor> speciesToColor;
|
||||
|
||||
|
||||
QStringList getSpeciesNamesAlphabetical() const;
|
||||
double getSpeciesFrequency(const QString&, const QString&) const;
|
||||
QMap<int, double> getLevelFrequencies(const QString &, const QString &) const;
|
||||
LevelRange getLevelRange(const QString &, const QString &) const;
|
||||
bool usesGroupLabels() const;
|
||||
|
||||
void clearTableData();
|
||||
void readTable();
|
||||
QChart* createSpeciesDistributionChart();
|
||||
QChart* createLevelDistributionChart();
|
||||
QBarSet* createLevelDistributionBarSet(const QString &, const QString &, bool);
|
||||
void refreshSpeciesDistributionChart();
|
||||
void refreshLevelDistributionChart();
|
||||
|
||||
void saveSpeciesColors(const QList<QBarSet*> &);
|
||||
void applySpeciesColors(const QList<QBarSet*> &);
|
||||
QChart::ChartTheme currentTheme() const;
|
||||
void updateTheme();
|
||||
void limitChartAnimation(QChart*);
|
||||
|
||||
void showHelpDialog();
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
// As of writing our static Qt build for Windows doesn't include the QtCharts module, so we dummy the class out here.
|
||||
// The charts module is additionally excluded from Windows in porymap.pro
|
||||
#define DISABLE_CHARTS_MODULE
|
||||
|
||||
class WildMonChart : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit WildMonChart(QWidget *, const EncounterTableModel *) {};
|
||||
~WildMonChart() {};
|
||||
|
||||
public slots:
|
||||
void setTable(const EncounterTableModel *) {};
|
||||
void clearTable() {};
|
||||
void refresh() {};
|
||||
};
|
||||
|
||||
#endif // __has_include(<QtCharts>)
|
||||
|
||||
#endif // WILDMONCHART_H
|
22
porymap.pro
22
porymap.pro
|
@ -6,6 +6,10 @@
|
|||
|
||||
QT += core gui qml network
|
||||
|
||||
!win32 {
|
||||
QT += charts
|
||||
}
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = porymap
|
||||
|
@ -24,6 +28,7 @@ SOURCES += src/core/block.cpp \
|
|||
src/core/heallocation.cpp \
|
||||
src/core/imageexport.cpp \
|
||||
src/core/map.cpp \
|
||||
src/core/mapconnection.cpp \
|
||||
src/core/maplayout.cpp \
|
||||
src/core/mapparser.cpp \
|
||||
src/core/metatile.cpp \
|
||||
|
@ -46,13 +51,16 @@ SOURCES += src/core/block.cpp \
|
|||
src/scriptapi/apiutility.cpp \
|
||||
src/scriptapi/scripting.cpp \
|
||||
src/ui/aboutporymap.cpp \
|
||||
src/ui/connectionslistitem.cpp \
|
||||
src/ui/customscriptseditor.cpp \
|
||||
src/ui/customscriptslistitem.cpp \
|
||||
src/ui/divingmappixmapitem.cpp \
|
||||
src/ui/draggablepixmapitem.cpp \
|
||||
src/ui/bordermetatilespixmapitem.cpp \
|
||||
src/ui/collisionpixmapitem.cpp \
|
||||
src/ui/connectionpixmapitem.cpp \
|
||||
src/ui/currentselectedmetatilespixmapitem.cpp \
|
||||
src/ui/newmapconnectiondialog.cpp \
|
||||
src/ui/overlay.cpp \
|
||||
src/ui/prefab.cpp \
|
||||
src/ui/projectsettingseditor.cpp \
|
||||
|
@ -107,7 +115,8 @@ SOURCES += src/core/block.cpp \
|
|||
src/settings.cpp \
|
||||
src/log.cpp \
|
||||
src/ui/uintspinbox.cpp \
|
||||
src/ui/updatepromoter.cpp
|
||||
src/ui/updatepromoter.cpp \
|
||||
src/ui/wildmonchart.cpp
|
||||
|
||||
HEADERS += include/core/block.h \
|
||||
include/core/bitpacker.h \
|
||||
|
@ -140,13 +149,16 @@ HEADERS += include/core/block.h \
|
|||
include/lib/orderedmap.h \
|
||||
include/lib/orderedjson.h \
|
||||
include/ui/aboutporymap.h \
|
||||
include/ui/connectionslistitem.h \
|
||||
include/ui/customscriptseditor.h \
|
||||
include/ui/customscriptslistitem.h \
|
||||
include/ui/divingmappixmapitem.h \
|
||||
include/ui/draggablepixmapitem.h \
|
||||
include/ui/bordermetatilespixmapitem.h \
|
||||
include/ui/collisionpixmapitem.h \
|
||||
include/ui/connectionpixmapitem.h \
|
||||
include/ui/currentselectedmetatilespixmapitem.h \
|
||||
include/ui/newmapconnectiondialog.h \
|
||||
include/ui/prefabframe.h \
|
||||
include/ui/projectsettingseditor.h \
|
||||
include/ui/regionmaplayoutpixmapitem.h \
|
||||
|
@ -204,9 +216,12 @@ HEADERS += include/core/block.h \
|
|||
include/settings.h \
|
||||
include/log.h \
|
||||
include/ui/uintspinbox.h \
|
||||
include/ui/updatepromoter.h
|
||||
include/ui/updatepromoter.h \
|
||||
include/ui/wildmonchart.h
|
||||
|
||||
FORMS += forms/mainwindow.ui \
|
||||
forms/connectionslistitem.ui \
|
||||
forms/newmapconnectiondialog.ui \
|
||||
forms/prefabcreationdialog.ui \
|
||||
forms/prefabframe.ui \
|
||||
forms/tileseteditor.ui \
|
||||
|
@ -223,7 +238,8 @@ FORMS += forms/mainwindow.ui \
|
|||
forms/projectsettingseditor.ui \
|
||||
forms/customscriptseditor.ui \
|
||||
forms/customscriptslistitem.ui \
|
||||
forms/updatepromoter.ui
|
||||
forms/updatepromoter.ui \
|
||||
forms/wildmonchart.ui
|
||||
|
||||
RESOURCES += \
|
||||
resources/images.qrc \
|
||||
|
|
BIN
resources/icons/help.ico
Executable file
BIN
resources/icons/help.ico
Executable file
Binary file not shown.
After (image error) Size: 2.2 KiB |
BIN
resources/icons/map_go.ico
Executable file
BIN
resources/icons/map_go.ico
Executable file
Binary file not shown.
After (image error) Size: 1.9 KiB |
|
@ -20,6 +20,7 @@
|
|||
<file>icons/folder.ico</file>
|
||||
<file>icons/lock_edit.ico</file>
|
||||
<file>icons/unlock_edit.ico</file>
|
||||
<file>icons/help.ico</file>
|
||||
<file>icons/map_edited.ico</file>
|
||||
<file>icons/map_opened.ico</file>
|
||||
<file>icons/map.ico</file>
|
||||
|
@ -73,5 +74,6 @@
|
|||
<file>images/Entities_16x16.png</file>
|
||||
<file>images/pokemon_icon_placeholder.png</file>
|
||||
<file>icons/clipboard.ico</file>
|
||||
<file>icons/map_go.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
836
src/config.cpp
836
src/config.cpp
File diff suppressed because it is too large
Load diff
|
@ -47,9 +47,9 @@ uint16_t Block::rawValue() const {
|
|||
}
|
||||
|
||||
void Block::setLayout() {
|
||||
bitsMetatileId.setMask(projectConfig.getBlockMetatileIdMask());
|
||||
bitsCollision.setMask(projectConfig.getBlockCollisionMask());
|
||||
bitsElevation.setMask(projectConfig.getBlockElevationMask());
|
||||
bitsMetatileId.setMask(projectConfig.blockMetatileIdMask);
|
||||
bitsCollision.setMask(projectConfig.blockCollisionMask);
|
||||
bitsElevation.setMask(projectConfig.blockElevationMask);
|
||||
}
|
||||
|
||||
bool Block::operator ==(Block other) const {
|
||||
|
|
|
@ -330,7 +330,7 @@ void EventCreate::redo() {
|
|||
|
||||
// select this event
|
||||
editor->selected_events->clear();
|
||||
editor->selectMapEvent(event->getPixmapItem(), false);
|
||||
editor->selectMapEvent(event->getPixmapItem());
|
||||
}
|
||||
|
||||
void EventCreate::undo() {
|
||||
|
@ -568,3 +568,205 @@ void ScriptEditLayout::undo() {
|
|||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionMove::MapConnectionMove(MapConnection *connection, int newOffset, unsigned actionId,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Move Map Connection");
|
||||
|
||||
this->connection = connection;
|
||||
this->oldOffset = connection->offset();
|
||||
this->newOffset = newOffset;
|
||||
|
||||
this->mirrored = porymapConfig.mirrorConnectingMaps;
|
||||
|
||||
this->actionId = actionId;
|
||||
}
|
||||
|
||||
void MapConnectionMove::redo() {
|
||||
QUndoCommand::redo();
|
||||
if (this->connection)
|
||||
this->connection->setOffset(this->newOffset, this->mirrored);
|
||||
}
|
||||
|
||||
void MapConnectionMove::undo() {
|
||||
if (this->connection)
|
||||
this->connection->setOffset(this->oldOffset, this->mirrored);
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
bool MapConnectionMove::mergeWith(const QUndoCommand *command) {
|
||||
if (this->id() != command->id())
|
||||
return false;
|
||||
|
||||
const MapConnectionMove *other = static_cast<const MapConnectionMove *>(command);
|
||||
if (this->connection != other->connection)
|
||||
return false;
|
||||
if (this->actionId != other->actionId)
|
||||
return false;
|
||||
|
||||
this->newOffset = other->newOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionChangeDirection::MapConnectionChangeDirection(MapConnection *connection, QString newDirection,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Change Map Connection Direction");
|
||||
|
||||
this->connection = connection;
|
||||
|
||||
this->oldDirection = connection->direction();
|
||||
this->newDirection = newDirection;
|
||||
|
||||
this->oldOffset = connection->offset();
|
||||
|
||||
// If the direction changes between vertical/horizontal then the old offset may not make sense, so we reset it.
|
||||
if (MapConnection::isHorizontal(this->oldDirection) != MapConnection::isHorizontal(this->newDirection)
|
||||
|| MapConnection::isVertical(this->oldDirection) != MapConnection::isVertical(this->newDirection)) {
|
||||
this->newOffset = 0;
|
||||
} else {
|
||||
this->newOffset = oldOffset;
|
||||
}
|
||||
|
||||
this->mirrored = porymapConfig.mirrorConnectingMaps;
|
||||
}
|
||||
|
||||
void MapConnectionChangeDirection::redo() {
|
||||
QUndoCommand::redo();
|
||||
if (this->connection) {
|
||||
this->connection->setDirection(this->newDirection, this->mirrored);
|
||||
this->connection->setOffset(this->newOffset, this->mirrored);
|
||||
}
|
||||
}
|
||||
|
||||
void MapConnectionChangeDirection::undo() {
|
||||
if (this->connection) {
|
||||
this->connection->setDirection(this->oldDirection, this->mirrored);
|
||||
this->connection->setOffset(this->oldOffset, this->mirrored);
|
||||
}
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionChangeMap::MapConnectionChangeMap(MapConnection *connection, QString newMapName,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Change Map Connection Map");
|
||||
|
||||
this->connection = connection;
|
||||
|
||||
this->oldMapName = connection->targetMapName();
|
||||
this->newMapName = newMapName;
|
||||
|
||||
this->oldOffset = connection->offset();
|
||||
this->newOffset = 0; // The old offset may not make sense, so we reset it
|
||||
|
||||
this->mirrored = porymapConfig.mirrorConnectingMaps;
|
||||
}
|
||||
|
||||
void MapConnectionChangeMap::redo() {
|
||||
QUndoCommand::redo();
|
||||
if (this->connection) {
|
||||
this->connection->setTargetMapName(this->newMapName, this->mirrored);
|
||||
this->connection->setOffset(this->newOffset, this->mirrored);
|
||||
}
|
||||
}
|
||||
|
||||
void MapConnectionChangeMap::undo() {
|
||||
if (this->connection) {
|
||||
this->connection->setTargetMapName(this->oldMapName, this->mirrored);
|
||||
this->connection->setOffset(this->oldOffset, this->mirrored);
|
||||
}
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionAdd::MapConnectionAdd(Map *map, MapConnection *connection,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Add Map Connection");
|
||||
|
||||
this->map = map;
|
||||
this->connection = connection;
|
||||
|
||||
// Set this now because it's needed to create a mirror below.
|
||||
// It would otherwise be set by Map::addConnection.
|
||||
this->connection->setParentMap(this->map, false);
|
||||
|
||||
if (porymapConfig.mirrorConnectingMaps) {
|
||||
this->mirror = this->connection->createMirror();
|
||||
this->mirrorMap = this->connection->targetMap();
|
||||
}
|
||||
}
|
||||
|
||||
void MapConnectionAdd::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
this->map->addConnection(this->connection);
|
||||
if (this->mirrorMap)
|
||||
this->mirrorMap->addConnection(this->mirror);
|
||||
}
|
||||
|
||||
void MapConnectionAdd::undo() {
|
||||
if (this->mirrorMap) {
|
||||
// We can't guarantee that the mirror we created earlier is still our connection's
|
||||
// mirror because there is no strict source->mirror pairing for map connections
|
||||
// (a different identical map connection can take its place during any mirrored change).
|
||||
if (!MapConnection::areMirrored(this->connection, this->mirror))
|
||||
this->mirror = this->connection->findMirror();
|
||||
|
||||
this->mirrorMap->removeConnection(this->mirror);
|
||||
}
|
||||
this->map->removeConnection(this->connection);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
MapConnectionRemove::MapConnectionRemove(Map *map, MapConnection *connection,
|
||||
QUndoCommand *parent) : QUndoCommand(parent) {
|
||||
setText("Remove Map Connection");
|
||||
|
||||
this->map = map;
|
||||
this->connection = connection;
|
||||
|
||||
if (porymapConfig.mirrorConnectingMaps) {
|
||||
this->mirror = this->connection->findMirror();
|
||||
this->mirrorMap = this->connection->targetMap();
|
||||
}
|
||||
}
|
||||
|
||||
void MapConnectionRemove::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (this->mirrorMap) {
|
||||
// See comment in MapConnectionAdd::undo
|
||||
if (!MapConnection::areMirrored(this->connection, this->mirror))
|
||||
this->mirror = this->connection->findMirror();
|
||||
|
||||
this->mirrorMap->removeConnection(this->mirror);
|
||||
}
|
||||
this->map->removeConnection(this->connection);
|
||||
}
|
||||
|
||||
void MapConnectionRemove::undo() {
|
||||
this->map->addConnection(this->connection);
|
||||
if (this->mirrorMap)
|
||||
this->mirrorMap->addConnection(this->mirror);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,21 @@
|
|||
|
||||
QMap<Event::Group, const QPixmap*> Event::icons;
|
||||
|
||||
Event* Event::create(Event::Type type) {
|
||||
switch (type) {
|
||||
case Event::Type::Object: return new ObjectEvent();
|
||||
case Event::Type::CloneObject: return new CloneObjectEvent();
|
||||
case Event::Type::Warp: return new WarpEvent();
|
||||
case Event::Type::Trigger: return new TriggerEvent();
|
||||
case Event::Type::WeatherTrigger: return new WeatherTriggerEvent();
|
||||
case Event::Type::Sign: return new SignEvent();
|
||||
case Event::Type::HiddenItem: return new HiddenItemEvent();
|
||||
case Event::Type::SecretBase: return new SecretBaseEvent();
|
||||
case Event::Type::HealLocation: return new HealLocationEvent();
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Event::~Event() {
|
||||
if (this->eventFrame)
|
||||
this->eventFrame->deleteLater();
|
||||
|
@ -35,7 +50,7 @@ int Event::getEventIndex() {
|
|||
void Event::setDefaultValues(Project *) {
|
||||
this->setX(0);
|
||||
this->setY(0);
|
||||
this->setElevation(projectConfig.getDefaultElevation());
|
||||
this->setElevation(projectConfig.defaultElevation);
|
||||
}
|
||||
|
||||
void Event::readCustomValues(QJsonObject values) {
|
||||
|
@ -195,7 +210,7 @@ EventFrame *ObjectEvent::createEventFrame() {
|
|||
OrderedJson::object ObjectEvent::buildEventJson(Project *) {
|
||||
OrderedJson::object objectJson;
|
||||
|
||||
if (projectConfig.getEventCloneObjectEnabled()) {
|
||||
if (projectConfig.eventCloneObjectEnabled) {
|
||||
objectJson["type"] = "object";
|
||||
}
|
||||
objectJson["graphics_id"] = this->getGfx();
|
||||
|
@ -259,7 +274,7 @@ const QSet<QString> expectedObjectFields = {
|
|||
QSet<QString> ObjectEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedObjectFields;
|
||||
if (projectConfig.getEventCloneObjectEnabled()) {
|
||||
if (projectConfig.eventCloneObjectEnabled) {
|
||||
expectedFields.insert("type");
|
||||
}
|
||||
expectedFields << "x" << "y";
|
||||
|
@ -788,10 +803,10 @@ OrderedJson::object HiddenItemEvent::buildEventJson(Project *) {
|
|||
hiddenItemJson["elevation"] = this->getElevation();
|
||||
hiddenItemJson["item"] = this->getItem();
|
||||
hiddenItemJson["flag"] = this->getFlag();
|
||||
if (projectConfig.getHiddenItemQuantityEnabled()) {
|
||||
if (projectConfig.hiddenItemQuantityEnabled) {
|
||||
hiddenItemJson["quantity"] = this->getQuantity();
|
||||
}
|
||||
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
|
||||
if (projectConfig.hiddenItemRequiresItemfinderEnabled) {
|
||||
hiddenItemJson["underfoot"] = this->getUnderfoot();
|
||||
}
|
||||
|
||||
|
@ -806,10 +821,10 @@ bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) {
|
|||
this->setElevation(ParseUtil::jsonToInt(json["elevation"]));
|
||||
this->setItem(ParseUtil::jsonToQString(json["item"]));
|
||||
this->setFlag(ParseUtil::jsonToQString(json["flag"]));
|
||||
if (projectConfig.getHiddenItemQuantityEnabled()) {
|
||||
if (projectConfig.hiddenItemQuantityEnabled) {
|
||||
this->setQuantity(ParseUtil::jsonToInt(json["quantity"]));
|
||||
}
|
||||
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
|
||||
if (projectConfig.hiddenItemRequiresItemfinderEnabled) {
|
||||
this->setUnderfoot(ParseUtil::jsonToBool(json["underfoot"]));
|
||||
}
|
||||
|
||||
|
@ -821,10 +836,10 @@ bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) {
|
|||
void HiddenItemEvent::setDefaultValues(Project *project) {
|
||||
this->setItem(project->itemNames.value(0, "0"));
|
||||
this->setFlag(project->flagNames.value(0, "0"));
|
||||
if (projectConfig.getHiddenItemQuantityEnabled()) {
|
||||
if (projectConfig.hiddenItemQuantityEnabled) {
|
||||
this->setQuantity(1);
|
||||
}
|
||||
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
|
||||
if (projectConfig.hiddenItemRequiresItemfinderEnabled) {
|
||||
this->setUnderfoot(false);
|
||||
}
|
||||
}
|
||||
|
@ -839,10 +854,10 @@ const QSet<QString> expectedHiddenItemFields = {
|
|||
QSet<QString> HiddenItemEvent::getExpectedFields() {
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
expectedFields = expectedHiddenItemFields;
|
||||
if (projectConfig.getHiddenItemQuantityEnabled()) {
|
||||
if (projectConfig.hiddenItemQuantityEnabled) {
|
||||
expectedFields << "quantity";
|
||||
}
|
||||
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
|
||||
if (projectConfig.hiddenItemRequiresItemfinderEnabled) {
|
||||
expectedFields << "underfoot";
|
||||
}
|
||||
expectedFields << "x" << "y";
|
||||
|
@ -930,10 +945,10 @@ OrderedJson::object HealLocationEvent::buildEventJson(Project *) {
|
|||
}
|
||||
|
||||
void HealLocationEvent::setDefaultValues(Project *) {
|
||||
this->setElevation(projectConfig.getDefaultElevation());
|
||||
this->setElevation(projectConfig.defaultElevation);
|
||||
if (!this->getMap())
|
||||
return;
|
||||
bool respawnEnabled = projectConfig.getHealLocationRespawnDataEnabled();
|
||||
bool respawnEnabled = projectConfig.healLocationRespawnDataEnabled;
|
||||
const QString mapConstant = Map::mapConstantFromName(this->getMap()->name, false);
|
||||
const QString prefix = projectConfig.getIdentifier(respawnEnabled ? ProjectIdentifier::define_spawn_prefix
|
||||
: ProjectIdentifier::define_heal_locations_prefix);
|
||||
|
|
|
@ -24,7 +24,7 @@ HealLocation HealLocation::fromEvent(Event *fromEvent) {
|
|||
healLocation.index = event->getIndex();
|
||||
healLocation.x = event->getX();
|
||||
healLocation.y = event->getY();
|
||||
if (projectConfig.getHealLocationRespawnDataEnabled()) {
|
||||
if (projectConfig.healLocationRespawnDataEnabled) {
|
||||
healLocation.respawnNPC = event->getRespawnNPC();
|
||||
healLocation.respawnMap = Map::mapConstantFromName(event->getRespawnMap(), false);
|
||||
}
|
||||
|
|
172
src/core/map.cpp
172
src/core/map.cpp
|
@ -17,11 +17,9 @@ Map::Map(QObject *parent) : QObject(parent)
|
|||
}
|
||||
|
||||
Map::~Map() {
|
||||
// delete all associated events
|
||||
while (!ownedEvents.isEmpty()) {
|
||||
Event *last = ownedEvents.takeLast();
|
||||
if (last) delete last;
|
||||
}
|
||||
qDeleteAll(ownedEvents);
|
||||
ownedEvents.clear();
|
||||
deleteConnections();
|
||||
}
|
||||
|
||||
void Map::setName(QString mapName) {
|
||||
|
@ -69,40 +67,47 @@ int Map::getBorderHeight() {
|
|||
return layout->getBorderHeight();
|
||||
}
|
||||
|
||||
QPixmap Map::renderConnection(MapConnection connection, Layout * fromLayout) {
|
||||
int x, y, w, h;
|
||||
if (connection.direction == "up") {
|
||||
x = 0;
|
||||
y = getHeight() - BORDER_DISTANCE;
|
||||
w = getWidth();
|
||||
h = BORDER_DISTANCE;
|
||||
} else if (connection.direction == "down") {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = getWidth();
|
||||
h = BORDER_DISTANCE;
|
||||
} else if (connection.direction == "left") {
|
||||
x = getWidth() - BORDER_DISTANCE;
|
||||
y = 0;
|
||||
w = BORDER_DISTANCE;
|
||||
h = getHeight();
|
||||
} else if (connection.direction == "right") {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = BORDER_DISTANCE;
|
||||
h = getHeight();
|
||||
} else {
|
||||
// this should not happen
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = getWidth();
|
||||
h = getHeight();
|
||||
}
|
||||
// Get the portion of the map that can be rendered when rendered as a map connection.
|
||||
// Cardinal connections render the nearest segment of their map and within the bounds of the border draw distance,
|
||||
// Dive/Emerge connections are rendered normally within the bounds of their parent map.
|
||||
QRect Map::getConnectionRect(const QString &direction, Layout * fromLayout) {
|
||||
int x = 0, y = 0;
|
||||
int w = getWidth(), h = getHeight();
|
||||
|
||||
//render(true, fromLayout, QRect(x, y, w, h));
|
||||
//QImage connection_image = image.copy(x * 16, y * 16, w * 16, h * 16);
|
||||
return this->layout->render(true, fromLayout, QRect(x, y, w, h)).copy(x * 16, y * 16, w * 16, h * 16);
|
||||
//return QPixmap::fromImage(connection_image);
|
||||
if (direction == "up") {
|
||||
h = qMin(h, BORDER_DISTANCE);
|
||||
y = getHeight() - h;
|
||||
} else if (direction == "down") {
|
||||
h = qMin(h, BORDER_DISTANCE);
|
||||
} else if (direction == "left") {
|
||||
w = qMin(w, BORDER_DISTANCE);
|
||||
x = getWidth() - w;
|
||||
} else if (direction == "right") {
|
||||
w = qMin(w, BORDER_DISTANCE);
|
||||
} else if (MapConnection::isDiving(direction)) {
|
||||
if (fromLayout) {
|
||||
w = qMin(w, fromLayout->getWidth());
|
||||
h = qMin(h, fromLayout->getHeight());
|
||||
}
|
||||
} else {
|
||||
// Unknown direction
|
||||
return QRect();
|
||||
}
|
||||
return QRect(x, y, w, h);
|
||||
}
|
||||
|
||||
QPixmap Map::renderConnection(const QString &direction, Layout * fromLayout) {
|
||||
QRect bounds = getConnectionRect(direction, fromLayout);
|
||||
if (!bounds.isValid())
|
||||
return QPixmap();
|
||||
|
||||
// 'fromLayout' will be used in 'render' to get the palettes from the parent map.
|
||||
// Dive/Emerge connections render normally with their own palettes, so we ignore this.
|
||||
if (MapConnection::isDiving(direction))
|
||||
fromLayout = nullptr;
|
||||
|
||||
QPixmap connectionPixmap = this->layout->render(true, fromLayout, bounds);
|
||||
return connectionPixmap.copy(bounds.x() * 16, bounds.y() * 16, bounds.width() * 16, bounds.height() * 16);
|
||||
}
|
||||
|
||||
void Map::openScript(QString label) {
|
||||
|
@ -153,9 +158,9 @@ QStringList Map::getScriptLabels(Event::Group group) {
|
|||
}
|
||||
|
||||
QString Map::getScriptsFilePath() const {
|
||||
const bool usePoryscript = projectConfig.getUsePoryScript();
|
||||
const bool usePoryscript = projectConfig.usePoryScript;
|
||||
auto path = QDir::cleanPath(QString("%1/%2/%3/scripts")
|
||||
.arg(projectConfig.getProjectDir())
|
||||
.arg(projectConfig.projectDir)
|
||||
.arg(projectConfig.getFilePath(ProjectFilePath::data_map_folders))
|
||||
.arg(this->name));
|
||||
auto extension = Project::getScriptFileExtension(usePoryscript);
|
||||
|
@ -177,6 +182,72 @@ void Map::addEvent(Event *event) {
|
|||
if (!ownedEvents.contains(event)) ownedEvents.append(event);
|
||||
}
|
||||
|
||||
void Map::deleteConnections() {
|
||||
qDeleteAll(this->ownedConnections);
|
||||
this->ownedConnections.clear();
|
||||
this->connections.clear();
|
||||
}
|
||||
|
||||
QList<MapConnection*> Map::getConnections() const {
|
||||
return this->connections;
|
||||
}
|
||||
|
||||
void Map::addConnection(MapConnection *connection) {
|
||||
if (!connection || this->connections.contains(connection))
|
||||
return;
|
||||
|
||||
// Maps should only have one Dive/Emerge connection at a time.
|
||||
// (Users can technically have more by editing their data manually, but we will only display one at a time)
|
||||
// Any additional connections being added (this can happen via mirroring) are tracked for deleting but otherwise ignored.
|
||||
if (MapConnection::isDiving(connection->direction())) {
|
||||
for (auto i : this->connections) {
|
||||
if (i->direction() == connection->direction()) {
|
||||
trackConnection(connection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadConnection(connection);
|
||||
modify();
|
||||
emit connectionAdded(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
void Map::loadConnection(MapConnection *connection) {
|
||||
if (!connection)
|
||||
return;
|
||||
|
||||
if (!this->connections.contains(connection))
|
||||
this->connections.append(connection);
|
||||
|
||||
trackConnection(connection);
|
||||
}
|
||||
|
||||
void Map::trackConnection(MapConnection *connection) {
|
||||
connection->setParentMap(this, false);
|
||||
|
||||
if (!this->ownedConnections.contains(connection)) {
|
||||
this->ownedConnections.insert(connection);
|
||||
connect(connection, &MapConnection::parentMapChanged, [=](Map *, Map *after) {
|
||||
if (after != this && after != nullptr) {
|
||||
// MapConnection's parent has been reassigned, it's no longer our responsibility
|
||||
this->ownedConnections.remove(connection);
|
||||
QObject::disconnect(connection, &MapConnection::parentMapChanged, this, nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// We retain ownership of this MapConnection until it's assigned to a new parent map.
|
||||
void Map::removeConnection(MapConnection *connection) {
|
||||
if (!this->connections.removeOne(connection))
|
||||
return;
|
||||
connection->setParentMap(nullptr, false);
|
||||
modify();
|
||||
emit connectionRemoved(connection);
|
||||
}
|
||||
|
||||
void Map::modify() {
|
||||
emit modified();
|
||||
}
|
||||
|
@ -188,3 +259,24 @@ void Map::clean() {
|
|||
bool Map::hasUnsavedChanges() {
|
||||
return !editHistory.isClean() || !this->layout->editHistory.isClean() || hasUnsavedDataChanges || !isPersistedToFile;
|
||||
}
|
||||
|
||||
void Map::pruneEditHistory() {
|
||||
// Edit history for map connections gets messy because edits on other maps can affect the current map.
|
||||
// To avoid complications we clear MapConnection edit history when the user opens a different map.
|
||||
// No other edits within a single map depend on MapConnections so they can be pruned safely.
|
||||
static const QSet<int> mapConnectionIds = {
|
||||
ID_MapConnectionMove,
|
||||
ID_MapConnectionChangeDirection,
|
||||
ID_MapConnectionChangeMap,
|
||||
ID_MapConnectionAdd,
|
||||
ID_MapConnectionRemove
|
||||
};
|
||||
for (int i = 0; i < this->editHistory.count(); i++) {
|
||||
// Qt really doesn't expect editing commands in the stack to be valid (fair).
|
||||
// A better future design might be to have separate edit histories per map tab,
|
||||
// and dumping the entire Connections tab history with QUndoStack::clear.
|
||||
auto command = const_cast<QUndoCommand*>(this->editHistory.command(i));
|
||||
if (mapConnectionIds.contains(command->id()))
|
||||
command->setObsolete(true);
|
||||
}
|
||||
}
|
||||
|
|
163
src/core/mapconnection.cpp
Normal file
163
src/core/mapconnection.cpp
Normal file
|
@ -0,0 +1,163 @@
|
|||
#include "mapconnection.h"
|
||||
#include "project.h"
|
||||
|
||||
QPointer<Project> MapConnection::project = nullptr;
|
||||
|
||||
const QMap<QString, QString> MapConnection::oppositeDirections = {
|
||||
{"up", "down"}, {"down", "up"},
|
||||
{"right", "left"}, {"left", "right"},
|
||||
{"dive", "emerge"}, {"emerge", "dive"}
|
||||
};
|
||||
|
||||
MapConnection::MapConnection(const QString &targetMapName, const QString &direction, int offset) {
|
||||
m_parentMap = nullptr;
|
||||
m_targetMapName = targetMapName;
|
||||
m_direction = direction;
|
||||
m_offset = offset;
|
||||
}
|
||||
|
||||
bool MapConnection::areMirrored(const MapConnection* a, const MapConnection* b) {
|
||||
if (!a || !b || !a->m_parentMap || !b->m_parentMap)
|
||||
return false;
|
||||
|
||||
return a->parentMapName() == b->m_targetMapName
|
||||
&& a->m_targetMapName == b->parentMapName()
|
||||
&& a->m_offset == -b->m_offset
|
||||
&& a->m_direction == oppositeDirection(b->m_direction);
|
||||
}
|
||||
|
||||
MapConnection* MapConnection::findMirror() {
|
||||
auto map = targetMap();
|
||||
if (!map)
|
||||
return nullptr;
|
||||
|
||||
// Find the matching connection in the connected map.
|
||||
// Note: There is no strict source -> mirror pairing, i.e. we are not guaranteed
|
||||
// to always get the same MapConnection if there are multiple identical copies.
|
||||
for (auto connection : map->getConnections()) {
|
||||
if (this != connection && areMirrored(this, connection))
|
||||
return connection;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MapConnection * MapConnection::createMirror() {
|
||||
auto mirror = new MapConnection(parentMapName(), oppositeDirection(m_direction), -m_offset);
|
||||
mirror->setParentMap(targetMap(), false);
|
||||
return mirror;
|
||||
}
|
||||
|
||||
void MapConnection::markMapEdited() {
|
||||
if (m_parentMap)
|
||||
m_parentMap->modify();
|
||||
}
|
||||
|
||||
Map* MapConnection::getMap(const QString& mapName) const {
|
||||
return project ? project->getMap(mapName) : nullptr;
|
||||
}
|
||||
|
||||
Map* MapConnection::targetMap() const {
|
||||
return getMap(m_targetMapName);
|
||||
}
|
||||
|
||||
QPixmap MapConnection::getPixmap() {
|
||||
auto map = targetMap();
|
||||
if (!map)
|
||||
return QPixmap();
|
||||
|
||||
return map->renderConnection(m_direction, m_parentMap ? m_parentMap->layout : nullptr);
|
||||
}
|
||||
|
||||
void MapConnection::setParentMap(Map* map, bool mirror) {
|
||||
if (map == m_parentMap)
|
||||
return;
|
||||
|
||||
if (mirror) {
|
||||
auto connection = findMirror();
|
||||
if (connection)
|
||||
connection->setTargetMapName(map ? map->name : QString(), false);
|
||||
}
|
||||
|
||||
if (m_parentMap)
|
||||
m_parentMap->removeConnection(this);
|
||||
|
||||
auto before = m_parentMap;
|
||||
m_parentMap = map;
|
||||
|
||||
if (m_parentMap)
|
||||
m_parentMap->addConnection(this);
|
||||
|
||||
emit parentMapChanged(before, m_parentMap);
|
||||
}
|
||||
|
||||
QString MapConnection::parentMapName() const {
|
||||
return m_parentMap ? m_parentMap->name : QString();
|
||||
}
|
||||
|
||||
void MapConnection::setTargetMapName(const QString &targetMapName, bool mirror) {
|
||||
if (targetMapName == m_targetMapName)
|
||||
return;
|
||||
|
||||
if (mirror) {
|
||||
auto connection = findMirror();
|
||||
if (connection)
|
||||
connection->setParentMap(getMap(targetMapName), false);
|
||||
}
|
||||
|
||||
auto before = m_targetMapName;
|
||||
m_targetMapName = targetMapName;
|
||||
emit targetMapNameChanged(before, m_targetMapName);
|
||||
markMapEdited();
|
||||
}
|
||||
|
||||
void MapConnection::setDirection(const QString &direction, bool mirror) {
|
||||
if (direction == m_direction)
|
||||
return;
|
||||
|
||||
if (mirror) {
|
||||
auto connection = findMirror();
|
||||
if (connection)
|
||||
connection->setDirection(oppositeDirection(direction), false);
|
||||
}
|
||||
|
||||
auto before = m_direction;
|
||||
m_direction = direction;
|
||||
emit directionChanged(before, m_direction);
|
||||
markMapEdited();
|
||||
}
|
||||
|
||||
void MapConnection::setOffset(int offset, bool mirror) {
|
||||
if (offset == m_offset)
|
||||
return;
|
||||
|
||||
if (mirror) {
|
||||
auto connection = findMirror();
|
||||
if (connection)
|
||||
connection->setOffset(-offset, false);
|
||||
}
|
||||
|
||||
auto before = m_offset;
|
||||
m_offset = offset;
|
||||
emit offsetChanged(before, m_offset);
|
||||
markMapEdited();
|
||||
}
|
||||
|
||||
const QStringList MapConnection::cardinalDirections = {
|
||||
"up", "down", "left", "right"
|
||||
};
|
||||
|
||||
bool MapConnection::isCardinal(const QString &direction) {
|
||||
return cardinalDirections.contains(direction);
|
||||
}
|
||||
|
||||
bool MapConnection::isHorizontal(const QString &direction) {
|
||||
return direction == "left" || direction == "right";
|
||||
}
|
||||
|
||||
bool MapConnection::isVertical(const QString &direction) {
|
||||
return direction == "up" || direction == "down";
|
||||
}
|
||||
|
||||
bool MapConnection::isDiving(const QString &direction) {
|
||||
return direction == "dive" || direction == "emerge";
|
||||
}
|
|
@ -100,7 +100,7 @@ uint32_t Metatile::getMaxAttributesMask() {
|
|||
{2, 0xFFFF},
|
||||
{4, 0xFFFFFFFF},
|
||||
};
|
||||
return maxMasks.value(projectConfig.getMetatileAttributesSize(), 0);
|
||||
return maxMasks.value(projectConfig.metatileAttributesSize, 0);
|
||||
}
|
||||
|
||||
void Metatile::setLayout(Project * project) {
|
||||
|
@ -109,10 +109,10 @@ void Metatile::setLayout(Project * project) {
|
|||
for (uint16_t i = Block::getMaxMetatileId(); i > 0; i /= 16)
|
||||
numMetatileIdChars++;
|
||||
|
||||
uint32_t behaviorMask = projectConfig.getMetatileBehaviorMask();
|
||||
uint32_t terrainTypeMask = projectConfig.getMetatileTerrainTypeMask();
|
||||
uint32_t encounterTypeMask = projectConfig.getMetatileEncounterTypeMask();
|
||||
uint32_t layerTypeMask = projectConfig.getMetatileLayerTypeMask();
|
||||
uint32_t behaviorMask = projectConfig.metatileBehaviorMask;
|
||||
uint32_t terrainTypeMask = projectConfig.metatileTerrainTypeMask;
|
||||
uint32_t encounterTypeMask = projectConfig.metatileEncounterTypeMask;
|
||||
uint32_t layerTypeMask = projectConfig.metatileLayerTypeMask;
|
||||
|
||||
// Calculate mask of bits not used by standard behaviors so we can preserve this data.
|
||||
uint32_t unusedMask = ~(behaviorMask | terrainTypeMask | encounterTypeMask | layerTypeMask);
|
||||
|
|
|
@ -80,7 +80,7 @@ QList<Metatile*> MetatileParser::parse(QString filepath, bool *error, bool prima
|
|||
|
||||
// AdvanceMap .bvd files only contain 8 tiles of data per metatile.
|
||||
// If the user has triple-layer metatiles enabled we need to fill the remaining 4 tiles ourselves.
|
||||
if (projectConfig.getTripleLayerMetatilesEnabled()) {
|
||||
if (projectConfig.tripleLayerMetatilesEnabled) {
|
||||
Tile tile = Tile();
|
||||
for (int j = 0; j < 4; j++)
|
||||
tiles.append(tile);
|
||||
|
|
|
@ -9,15 +9,10 @@
|
|||
static const int DefaultWaitTime = 120;
|
||||
|
||||
NetworkAccessManager::NetworkAccessManager(QObject * parent) : QNetworkAccessManager(parent) {
|
||||
// We store rate limit end times in the user's config so that Porymap will still respect them after a restart.
|
||||
// To avoid reading/writing to a local file during network operations, we only read/write the file when the
|
||||
// manager is created/destroyed respectively.
|
||||
this->rateLimitTimes = porymapConfig.getRateLimitTimes();
|
||||
this->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
};
|
||||
|
||||
NetworkAccessManager::~NetworkAccessManager() {
|
||||
porymapConfig.setRateLimitTimes(this->rateLimitTimes);
|
||||
qDeleteAll(this->cache);
|
||||
}
|
||||
|
||||
|
@ -47,8 +42,9 @@ NetworkReplyData * NetworkAccessManager::get(const QUrl &url) {
|
|||
data->m_url = url;
|
||||
|
||||
// If we are rate-limited, don't send a new request.
|
||||
if (this->rateLimitTimes.contains(url)) {
|
||||
auto time = this->rateLimitTimes.value(url);
|
||||
// We store rate limit end times in the user's config so that Porymap will still respect them after a restart.
|
||||
if (porymapConfig.rateLimitTimes.contains(url)) {
|
||||
auto time = porymapConfig.rateLimitTimes.value(url);
|
||||
if (!time.isNull() && time > QDateTime::currentDateTime()) {
|
||||
data->m_retryAfter = time;
|
||||
data->m_error = QString("Rate limit reached. Please try again after %1.").arg(data->m_retryAfter.toString());
|
||||
|
@ -56,7 +52,7 @@ NetworkReplyData * NetworkAccessManager::get(const QUrl &url) {
|
|||
return data;
|
||||
}
|
||||
// Rate limiting expired
|
||||
this->rateLimitTimes.remove(url);
|
||||
porymapConfig.rateLimitTimes.remove(url);
|
||||
}
|
||||
|
||||
QNetworkReply * reply = QNetworkAccessManager::get(this->getRequest(url));
|
||||
|
@ -117,7 +113,7 @@ void NetworkAccessManager::processReply(QNetworkReply * reply, NetworkReplyData
|
|||
data->m_error = "Service busy or unavailable. ";
|
||||
}
|
||||
data->m_error.append(QString("Please try again after %1.").arg(data->m_retryAfter.toString()));
|
||||
this->rateLimitTimes.insert(url, data->m_retryAfter);
|
||||
porymapConfig.rateLimitTimes.insert(url, data->m_retryAfter);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -129,7 +125,7 @@ void NetworkAccessManager::processReply(QNetworkReply * reply, NetworkReplyData
|
|||
data->m_retryAfter = ok ? QDateTime::fromSecsSinceEpoch(limitReset).toLocalTime()
|
||||
: QDateTime::currentDateTime().addSecs(DefaultWaitTime);;
|
||||
data->m_error = QString("Too many requests. Please try again after %1.").arg(data->m_retryAfter.toString());
|
||||
this->rateLimitTimes.insert(url, data->m_retryAfter);
|
||||
porymapConfig.rateLimitTimes.insert(url, data->m_retryAfter);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,14 +79,25 @@ bool RegionMap::loadTilemap(poryjson::Json tilemapJson) {
|
|||
this->palette_path = tilemapObject["palette"].string_value();
|
||||
}
|
||||
|
||||
QImage tilesetFile(fullPath(this->tileset_path));
|
||||
if (tilesetFile.isNull()) {
|
||||
logError(QString("Failed to open region map tileset file '%1'.").arg(tileset_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tilesetFile.width() < 8 || tilesetFile.height() < 8) {
|
||||
logError(QString("Region map tileset file '%1' must be at least 8x8.").arg(tileset_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile tilemapFile(fullPath(this->tilemap_path));
|
||||
if (!tilemapFile.open(QIODevice::ReadOnly)) {
|
||||
logError(QString("Failed to open region map tilemap file %1.").arg(tilemap_path));
|
||||
logError(QString("Failed to open region map tilemap file '%1'.").arg(tilemap_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tilemapFile.size() < tilemapBytes()) {
|
||||
logError(QString("The region map tilemap at %1 is too small.").arg(tilemap_path));
|
||||
logError(QString("The region map tilemap at '%1' is too small.").arg(tilemap_path));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -297,7 +308,7 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
|
|||
}
|
||||
setLayout("main", layout);
|
||||
} else {
|
||||
logError("Region map layout is not readable.");
|
||||
logError(QString("Failed to read region map layout from '%1'.").arg(this->layout_path));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ bool Tileset::appendToHeaders(QString root, QString friendlyName, bool usingAsm)
|
|||
dataString.append(QString("\t.4byte gTilesetTiles_%1\n").arg(friendlyName));
|
||||
dataString.append(QString("\t.4byte gTilesetPalettes_%1\n").arg(friendlyName));
|
||||
dataString.append(QString("\t.4byte gMetatiles_%1\n").arg(friendlyName));
|
||||
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
|
||||
if (projectConfig.baseGameVersion == BaseGameVersion::pokefirered) {
|
||||
dataString.append("\t.4byte NULL @ animation callback\n");
|
||||
dataString.append(QString("\t.4byte gMetatileAttributes_%1\n").arg(friendlyName));
|
||||
} else {
|
||||
|
@ -248,13 +248,13 @@ bool Tileset::appendToHeaders(QString root, QString friendlyName, bool usingAsm)
|
|||
} else {
|
||||
// Append to C file
|
||||
dataString.append(QString("const struct Tileset %1 =\n{\n").arg(this->name));
|
||||
if (projectConfig.getTilesetsHaveIsCompressed()) dataString.append(" .isCompressed = TRUE,\n");
|
||||
if (projectConfig.tilesetsHaveIsCompressed) dataString.append(" .isCompressed = TRUE,\n");
|
||||
dataString.append(QString(" .isSecondary = %1,\n").arg(isSecondaryStr));
|
||||
dataString.append(QString(" .tiles = gTilesetTiles_%1,\n").arg(friendlyName));
|
||||
dataString.append(QString(" .palettes = gTilesetPalettes_%1,\n").arg(friendlyName));
|
||||
dataString.append(QString(" .metatiles = gMetatiles_%1,\n").arg(friendlyName));
|
||||
dataString.append(QString(" .metatileAttributes = gMetatileAttributes_%1,\n").arg(friendlyName));
|
||||
if (projectConfig.getTilesetsHaveCallback()) dataString.append(" .callback = NULL,\n");
|
||||
if (projectConfig.tilesetsHaveCallback) dataString.append(" .callback = NULL,\n");
|
||||
dataString.append("};\n");
|
||||
}
|
||||
file.write(dataString.toUtf8());
|
||||
|
@ -325,7 +325,7 @@ bool Tileset::appendToMetatiles(QString root, QString friendlyName, bool usingAs
|
|||
} else {
|
||||
// Append to C file
|
||||
dataString.append(QString("const u16 gMetatiles_%1[] = INCBIN_U16(\"%2\");\n").arg(friendlyName, metatilesPath));
|
||||
QString numBits = QString::number(projectConfig.getMetatileAttributesSize() * 8);
|
||||
QString numBits = QString::number(projectConfig.metatileAttributesSize * 8);
|
||||
dataString.append(QString("const u%1 gMetatileAttributes_%2[] = INCBIN_U%1(\"%3\");\n").arg(numBits, friendlyName, metatileAttrsPath));
|
||||
}
|
||||
file.write(dataString.toUtf8());
|
||||
|
@ -358,7 +358,7 @@ QHash<int, QString> Tileset::getHeaderMemberMap(bool usingAsm)
|
|||
int paddingOffset = usingAsm ? 1 : 0;
|
||||
|
||||
// The position of metatileAttributes changes between games
|
||||
bool isPokefirered = (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered);
|
||||
bool isPokefirered = (projectConfig.baseGameVersion == BaseGameVersion::pokefirered);
|
||||
int metatileAttrPosition = (isPokefirered ? 6 : 5) + paddingOffset;
|
||||
|
||||
auto map = QHash<int, QString>();
|
||||
|
|
1066
src/editor.cpp
1066
src/editor.cpp
File diff suppressed because it is too large
Load diff
1082
src/mainwindow.cpp
1082
src/mainwindow.cpp
File diff suppressed because it is too large
Load diff
312
src/project.cpp
312
src/project.cpp
|
@ -50,7 +50,7 @@ Project::~Project()
|
|||
void Project::initSignals() {
|
||||
// detect changes to specific filepaths being monitored
|
||||
QObject::connect(&fileWatcher, &QFileSystemWatcher::fileChanged, [this](QString changed){
|
||||
if (!porymapConfig.getMonitorFiles()) return;
|
||||
if (!porymapConfig.monitorFiles) return;
|
||||
if (modifiedFileTimestamps.contains(changed)) {
|
||||
if (QDateTime::currentMSecsSinceEpoch() < modifiedFileTimestamps[changed]) {
|
||||
return;
|
||||
|
@ -78,7 +78,7 @@ void Project::initSignals() {
|
|||
emit reloadProject();
|
||||
} else if (choice == QMessageBox::No) {
|
||||
if (showAgainCheck.isChecked()) {
|
||||
porymapConfig.setMonitorFiles(false);
|
||||
porymapConfig.monitorFiles = false;
|
||||
emit uncheckMonitorFilesAction();
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +92,61 @@ void Project::set_root(QString dir) {
|
|||
this->parser.set_root(dir);
|
||||
}
|
||||
|
||||
// Before attempting the initial project load we should check for a few notable files.
|
||||
// If all are missing then we can warn the user, they may have accidentally selected the wrong folder.
|
||||
bool Project::sanityCheck() {
|
||||
// The goal with the file selection is to pick files that are important enough that any reasonable project would have
|
||||
// at least 1 in the expected location, but unique enough that they're unlikely to overlap with a completely unrelated
|
||||
// directory (e.g. checking for 'data/maps/' is a bad choice because it's too generic, pokeyellow would pass for instance)
|
||||
static const QSet<ProjectFilePath> pathsToCheck = {
|
||||
ProjectFilePath::json_map_groups,
|
||||
ProjectFilePath::json_layouts,
|
||||
ProjectFilePath::tilesets_headers,
|
||||
ProjectFilePath::global_fieldmap,
|
||||
};
|
||||
for (auto pathId : pathsToCheck) {
|
||||
const QString path = QString("%1/%2").arg(this->root).arg(projectConfig.getFilePath(pathId));
|
||||
QFileInfo fileInfo(path);
|
||||
if (fileInfo.exists() && fileInfo.isFile())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Project::load() {
|
||||
this->disabledSettingsNames.clear();
|
||||
bool success = readMapLayouts()
|
||||
&& readRegionMapSections()
|
||||
&& readItemNames()
|
||||
&& readFlagNames()
|
||||
&& readVarNames()
|
||||
&& readMovementTypes()
|
||||
&& readInitialFacingDirections()
|
||||
&& readMapTypes()
|
||||
&& readMapBattleScenes()
|
||||
&& readWeatherNames()
|
||||
&& readCoordEventWeatherNames()
|
||||
&& readSecretBaseIds()
|
||||
&& readBgEventFacingDirections()
|
||||
&& readTrainerTypes()
|
||||
&& readMetatileBehaviors()
|
||||
&& readFieldmapProperties()
|
||||
&& readFieldmapMasks()
|
||||
&& readTilesetLabels()
|
||||
&& readTilesetMetatileLabels()
|
||||
&& readHealLocations()
|
||||
&& readMiscellaneousConstants()
|
||||
&& readSpeciesIconPaths()
|
||||
&& readWildMonData()
|
||||
&& readEventScriptLabels()
|
||||
&& readObjEventGfxConstants()
|
||||
&& readEventGraphics()
|
||||
&& readSongNames()
|
||||
&& readMapGroups();
|
||||
applyParsedLimits();
|
||||
return success;
|
||||
}
|
||||
|
||||
QString Project::getProjectTitle() {
|
||||
if (!root.isNull()) {
|
||||
return root.section('/', -1);
|
||||
|
@ -128,6 +183,9 @@ void Project::clearLayoutsTable() {
|
|||
}
|
||||
|
||||
Map* Project::loadMap(QString map_name) {
|
||||
if (map_name == DYNAMIC_MAP_NAME)
|
||||
return nullptr;
|
||||
|
||||
Map *map;
|
||||
if (mapCache.contains(map_name)) {
|
||||
map = mapCache.value(map_name);
|
||||
|
@ -140,17 +198,16 @@ Map* Project::loadMap(QString map_name) {
|
|||
map->setName(map_name);
|
||||
}
|
||||
|
||||
if (!(loadMapData(map) && loadMapLayout(map)))
|
||||
if (!(loadMapData(map) && loadMapLayout(map))){
|
||||
delete map;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mapCache.insert(map_name, map);
|
||||
emit mapLoaded(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
void Project::setNewMapConnections(Map *map) {
|
||||
map->connections.clear();
|
||||
}
|
||||
|
||||
const QSet<QString> defaultTopLevelMapFields = {
|
||||
"id",
|
||||
"name",
|
||||
|
@ -173,13 +230,13 @@ const QSet<QString> defaultTopLevelMapFields = {
|
|||
|
||||
QSet<QString> Project::getTopLevelMapFields() {
|
||||
QSet<QString> topLevelMapFields = defaultTopLevelMapFields;
|
||||
if (projectConfig.getMapAllowFlagsEnabled()) {
|
||||
if (projectConfig.mapAllowFlagsEnabled) {
|
||||
topLevelMapFields.insert("allow_cycling");
|
||||
topLevelMapFields.insert("allow_escaping");
|
||||
topLevelMapFields.insert("allow_running");
|
||||
}
|
||||
|
||||
if (projectConfig.getFloorNumberEnabled()) {
|
||||
if (projectConfig.floorNumberEnabled) {
|
||||
topLevelMapFields.insert("floor_number");
|
||||
}
|
||||
return topLevelMapFields;
|
||||
|
@ -208,12 +265,12 @@ bool Project::loadMapData(Map* map) {
|
|||
map->show_location = ParseUtil::jsonToBool(mapObj["show_map_name"]);
|
||||
map->battle_scene = ParseUtil::jsonToQString(mapObj["battle_scene"]);
|
||||
|
||||
if (projectConfig.getMapAllowFlagsEnabled()) {
|
||||
if (projectConfig.mapAllowFlagsEnabled) {
|
||||
map->allowBiking = ParseUtil::jsonToBool(mapObj["allow_cycling"]);
|
||||
map->allowEscaping = ParseUtil::jsonToBool(mapObj["allow_escaping"]);
|
||||
map->allowRunning = ParseUtil::jsonToBool(mapObj["allow_running"]);
|
||||
}
|
||||
if (projectConfig.getFloorNumberEnabled()) {
|
||||
if (projectConfig.floorNumberEnabled) {
|
||||
map->floorNumber = ParseUtil::jsonToInt(mapObj["floor_number"]);
|
||||
}
|
||||
map->sharedEventsMap = ParseUtil::jsonToQString(mapObj["shared_events_map"]);
|
||||
|
@ -222,11 +279,10 @@ bool Project::loadMapData(Map* map) {
|
|||
// Events
|
||||
map->events[Event::Group::Object].clear();
|
||||
QJsonArray objectEventsArr = mapObj["object_events"].toArray();
|
||||
bool hasCloneObjects = projectConfig.getEventCloneObjectEnabled();
|
||||
for (int i = 0; i < objectEventsArr.size(); i++) {
|
||||
QJsonObject event = objectEventsArr[i].toObject();
|
||||
// If clone objects are not enabled then no type field is present
|
||||
QString type = hasCloneObjects ? ParseUtil::jsonToQString(event["type"]) : "object";
|
||||
QString type = projectConfig.eventCloneObjectEnabled ? ParseUtil::jsonToQString(event["type"]) : "object";
|
||||
if (type.isEmpty() || type == "object") {
|
||||
ObjectEvent *object = new ObjectEvent();
|
||||
object->loadFromJson(event, this);
|
||||
|
@ -308,11 +364,11 @@ bool Project::loadMapData(Map* map) {
|
|||
heal->setMap(map);
|
||||
heal->setX(loc.x);
|
||||
heal->setY(loc.y);
|
||||
heal->setElevation(projectConfig.getDefaultElevation());
|
||||
heal->setElevation(projectConfig.defaultElevation);
|
||||
heal->setLocationName(loc.mapName);
|
||||
heal->setIdName(loc.idName);
|
||||
heal->setIndex(loc.index);
|
||||
if (projectConfig.getHealLocationRespawnDataEnabled()) {
|
||||
if (projectConfig.healLocationRespawnDataEnabled) {
|
||||
heal->setRespawnMap(mapConstantsToMapNames.value(QString(mapPrefix + loc.respawnMap)));
|
||||
heal->setRespawnNPC(loc.respawnNPC);
|
||||
}
|
||||
|
@ -320,18 +376,17 @@ bool Project::loadMapData(Map* map) {
|
|||
}
|
||||
}
|
||||
|
||||
map->connections.clear();
|
||||
map->deleteConnections();
|
||||
QJsonArray connectionsArr = mapObj["connections"].toArray();
|
||||
if (!connectionsArr.isEmpty()) {
|
||||
for (int i = 0; i < connectionsArr.size(); i++) {
|
||||
QJsonObject connectionObj = connectionsArr[i].toObject();
|
||||
MapConnection *connection = new MapConnection;
|
||||
connection->direction = ParseUtil::jsonToQString(connectionObj["direction"]);
|
||||
connection->offset = ParseUtil::jsonToInt(connectionObj["offset"]);
|
||||
QString mapConstant = ParseUtil::jsonToQString(connectionObj["map"]);
|
||||
const QString direction = ParseUtil::jsonToQString(connectionObj["direction"]);
|
||||
int offset = ParseUtil::jsonToInt(connectionObj["offset"]);
|
||||
const QString mapConstant = ParseUtil::jsonToQString(connectionObj["map"]);
|
||||
if (mapConstantsToMapNames.contains(mapConstant)) {
|
||||
connection->map_name = mapConstantsToMapNames.value(mapConstant);
|
||||
map->connections.append(connection);
|
||||
// Successully read map connection
|
||||
map->loadConnection(new MapConnection(mapConstantsToMapNames.value(mapConstant), direction, offset));
|
||||
} else {
|
||||
logError(QString("Failed to find connected map for map constant '%1'").arg(mapConstant));
|
||||
}
|
||||
|
@ -526,7 +581,6 @@ bool Project::readMapLayouts() {
|
|||
"border_filepath",
|
||||
"blockdata_filepath",
|
||||
};
|
||||
bool useCustomBorderSize = projectConfig.getUseCustomBorderSize();
|
||||
for (int i = 0; i < layouts.size(); i++) {
|
||||
QJsonObject layoutObj = layouts[i].toObject();
|
||||
if (layoutObj.isEmpty())
|
||||
|
@ -567,7 +621,7 @@ bool Project::readMapLayouts() {
|
|||
return false;
|
||||
}
|
||||
layout->height = lheight;
|
||||
if (useCustomBorderSize) {
|
||||
if (projectConfig.useCustomBorderSize) {
|
||||
int bwidth = ParseUtil::jsonToInt(layoutObj["border_width"]);
|
||||
if (bwidth <= 0) { // 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG
|
||||
logWarn(QString("Invalid 'border_width' value '%1' for %2 in %3. Must be greater than 0. Using default (%4) instead.")
|
||||
|
@ -631,7 +685,6 @@ void Project::saveMapLayouts() {
|
|||
OrderedJson::object layoutsObj;
|
||||
layoutsObj["layouts_table_label"] = layoutsLabel;
|
||||
|
||||
bool useCustomBorderSize = projectConfig.getUseCustomBorderSize();
|
||||
OrderedJson::array layoutsArr;
|
||||
for (QString layoutId : mapLayoutsTableMaster) {
|
||||
Layout *layout = mapLayoutsMaster.value(layoutId);
|
||||
|
@ -640,7 +693,7 @@ void Project::saveMapLayouts() {
|
|||
layoutObj["name"] = layout->name;
|
||||
layoutObj["width"] = layout->width;
|
||||
layoutObj["height"] = layout->height;
|
||||
if (useCustomBorderSize) {
|
||||
if (projectConfig.useCustomBorderSize) {
|
||||
layoutObj["border_width"] = layout->border_width;
|
||||
layoutObj["border_height"] = layout->border_height;
|
||||
}
|
||||
|
@ -884,7 +937,7 @@ void Project::saveHealLocationsData(Map *map) {
|
|||
}
|
||||
|
||||
// Create the definition text for each data table
|
||||
bool respawnEnabled = projectConfig.getHealLocationRespawnDataEnabled();
|
||||
bool respawnEnabled = projectConfig.healLocationRespawnDataEnabled;
|
||||
const QString qualifiers = QString(healLocationDataQualifiers.isStatic ? "static " : "")
|
||||
+ QString(healLocationDataQualifiers.isConst ? "const " : "");
|
||||
|
||||
|
@ -1067,10 +1120,9 @@ void Project::saveTilesetMetatileAttributes(Tileset *tileset) {
|
|||
QFile attrs_file(tileset->metatile_attrs_path);
|
||||
if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
QByteArray data;
|
||||
int attrSize = projectConfig.getMetatileAttributesSize();
|
||||
for (Metatile *metatile : tileset->metatiles) {
|
||||
uint32_t attributes = metatile->getAttributes();
|
||||
for (int i = 0; i < attrSize; i++)
|
||||
for (int i = 0; i < projectConfig.metatileAttributesSize; i++)
|
||||
data.append(static_cast<char>(attributes >> (8 * i)));
|
||||
}
|
||||
attrs_file.write(data);
|
||||
|
@ -1206,7 +1258,7 @@ void Project::setNewLayoutBlockdata(Layout *layout) {
|
|||
layout->blockdata.clear();
|
||||
int width = layout->getWidth();
|
||||
int height = layout->getHeight();
|
||||
Block block(projectConfig.getDefaultMetatileId(), projectConfig.getDefaultCollision(), projectConfig.getDefaultElevation());
|
||||
Block block(projectConfig.defaultMetatileId, projectConfig.defaultCollision, projectConfig.defaultElevation);
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
layout->blockdata.append(block);
|
||||
}
|
||||
|
@ -1235,8 +1287,7 @@ void Project::setNewLayoutBorder(Layout *layout) {
|
|||
int width = layout->getBorderWidth();
|
||||
int height = layout->getBorderHeight();
|
||||
|
||||
const QList<uint16_t> configMetatileIds = projectConfig.getNewMapBorderMetatileIds();
|
||||
if (configMetatileIds.length() != width * height) {
|
||||
if (projectConfig.newMapBorderMetatileIds.length() != width * height) {
|
||||
// Border size doesn't match the number of default border metatiles.
|
||||
// Fill the border with empty metatiles.
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
|
@ -1245,7 +1296,7 @@ void Project::setNewLayoutBorder(Layout *layout) {
|
|||
} else {
|
||||
// Fill the border with the default metatiles from the config.
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
layout->border.append(configMetatileIds.at(i));
|
||||
layout->border.append(projectConfig.newMapBorderMetatileIds.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1288,18 +1339,17 @@ void Project::saveMap(Map *map) {
|
|||
}
|
||||
|
||||
// Create file data/maps/<map_name>/scripts.inc
|
||||
QString text = this->getScriptDefaultString(projectConfig.getUsePoryScript(), map->name);
|
||||
saveTextFile(mapDataDir + "/scripts" + this->getScriptFileExtension(projectConfig.getUsePoryScript()), text);
|
||||
QString text = this->getScriptDefaultString(projectConfig.usePoryScript, map->name);
|
||||
saveTextFile(mapDataDir + "/scripts" + this->getScriptFileExtension(projectConfig.usePoryScript), text);
|
||||
|
||||
bool usesTextFile = projectConfig.getCreateMapTextFileEnabled();
|
||||
if (usesTextFile) {
|
||||
if (projectConfig.createMapTextFileEnabled) {
|
||||
// Create file data/maps/<map_name>/text.inc
|
||||
saveTextFile(mapDataDir + "/text" + this->getScriptFileExtension(projectConfig.getUsePoryScript()), "\n");
|
||||
saveTextFile(mapDataDir + "/text" + this->getScriptFileExtension(projectConfig.usePoryScript), "\n");
|
||||
}
|
||||
|
||||
// Simply append to data/event_scripts.s.
|
||||
text = QString("\n\t.include \"%1%2/scripts.inc\"\n").arg(basePath, map->name);
|
||||
if (usesTextFile) {
|
||||
if (projectConfig.createMapTextFileEnabled) {
|
||||
text += QString("\t.include \"%1%2/text.inc\"\n").arg(basePath, map->name);
|
||||
}
|
||||
appendTextFile(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts), text);
|
||||
|
@ -1330,29 +1380,30 @@ void Project::saveMap(Map *map) {
|
|||
mapObj["requires_flash"] = map->requiresFlash;
|
||||
mapObj["weather"] = map->weather;
|
||||
mapObj["map_type"] = map->type;
|
||||
if (projectConfig.getMapAllowFlagsEnabled()) {
|
||||
if (projectConfig.mapAllowFlagsEnabled) {
|
||||
mapObj["allow_cycling"] = map->allowBiking;
|
||||
mapObj["allow_escaping"] = map->allowEscaping;
|
||||
mapObj["allow_running"] = map->allowRunning;
|
||||
}
|
||||
mapObj["show_map_name"] = map->show_location;
|
||||
if (projectConfig.getFloorNumberEnabled()) {
|
||||
if (projectConfig.floorNumberEnabled) {
|
||||
mapObj["floor_number"] = map->floorNumber;
|
||||
}
|
||||
mapObj["battle_scene"] = map->battle_scene;
|
||||
|
||||
// Connections
|
||||
if (map->connections.length() > 0) {
|
||||
auto connections = map->getConnections();
|
||||
if (connections.length() > 0) {
|
||||
OrderedJson::array connectionsArr;
|
||||
for (MapConnection* connection : map->connections) {
|
||||
if (mapNamesToMapConstants.contains(connection->map_name)) {
|
||||
for (auto connection : connections) {
|
||||
if (mapNamesToMapConstants.contains(connection->targetMapName())) {
|
||||
OrderedJson::object connectionObj;
|
||||
connectionObj["map"] = this->mapNamesToMapConstants.value(connection->map_name);
|
||||
connectionObj["offset"] = connection->offset;
|
||||
connectionObj["direction"] = connection->direction;
|
||||
connectionObj["map"] = this->mapNamesToMapConstants.value(connection->targetMapName());
|
||||
connectionObj["offset"] = connection->offset();
|
||||
connectionObj["direction"] = connection->direction();
|
||||
connectionsArr.append(connectionObj);
|
||||
} else {
|
||||
logError(QString("Failed to write map connection. '%1' is not a valid map name").arg(connection->map_name));
|
||||
logError(QString("Failed to write map connection. '%1' is not a valid map name").arg(connection->targetMapName()));
|
||||
}
|
||||
}
|
||||
mapObj["connections"] = connectionsArr;
|
||||
|
@ -1453,6 +1504,12 @@ void Project::saveAllDataStructures() {
|
|||
saveMapSections();
|
||||
saveMapConstantsHeader();
|
||||
saveWildMonData();
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
void Project::saveConfig() {
|
||||
projectConfig.save();
|
||||
userConfig.save();
|
||||
}
|
||||
|
||||
void Project::loadTilesetAssets(Tileset* tileset) {
|
||||
|
@ -1591,7 +1648,7 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
|
|||
if (attrs_file.open(QIODevice::ReadOnly)) {
|
||||
QByteArray data = attrs_file.readAll();
|
||||
int num_metatiles = tileset->metatiles.count();
|
||||
int attrSize = projectConfig.getMetatileAttributesSize();
|
||||
int attrSize = projectConfig.metatileAttributesSize;
|
||||
int num_metatileAttrs = data.length() / attrSize;
|
||||
if (num_metatiles != num_metatileAttrs) {
|
||||
logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(num_metatiles).arg(num_metatileAttrs).arg(tileset->name));
|
||||
|
@ -1723,15 +1780,43 @@ void Project::deleteFile(QString path) {
|
|||
}
|
||||
|
||||
bool Project::readWildMonData() {
|
||||
extraEncounterGroups.clear();
|
||||
wildMonFields.clear();
|
||||
wildMonData.clear();
|
||||
encounterGroupLabels.clear();
|
||||
this->extraEncounterGroups.clear();
|
||||
this->wildMonFields.clear();
|
||||
this->wildMonData.clear();
|
||||
this->encounterGroupLabels.clear();
|
||||
this->pokemonMinLevel = 0;
|
||||
this->pokemonMaxLevel = 100;
|
||||
this->maxEncounterRate = 2880/16;
|
||||
this->wildEncountersLoaded = false;
|
||||
if (!userConfig.getEncounterJsonActive()) {
|
||||
if (!userConfig.useEncounterJson) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read max encounter rate. The games multiply the encounter rate value in the map data by 16, so our input limit is the max/16.
|
||||
const QString encounterRateFile = projectConfig.getFilePath(ProjectFilePath::wild_encounter);
|
||||
const QString maxEncounterRateName = projectConfig.getIdentifier(ProjectIdentifier::define_max_encounter_rate);
|
||||
|
||||
fileWatcher.addPath(QString("%1/%2").arg(root).arg(encounterRateFile));
|
||||
auto defines = parser.readCDefinesByName(encounterRateFile, {maxEncounterRateName});
|
||||
if (defines.contains(maxEncounterRateName))
|
||||
this->maxEncounterRate = defines.value(maxEncounterRateName)/16;
|
||||
|
||||
// Read min/max level
|
||||
const QString levelRangeFile = projectConfig.getFilePath(ProjectFilePath::constants_pokemon);
|
||||
const QString minLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_min_level);
|
||||
const QString maxLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_max_level);
|
||||
|
||||
fileWatcher.addPath(QString("%1/%2").arg(root).arg(levelRangeFile));
|
||||
defines = parser.readCDefinesByName(levelRangeFile, {minLevelName, maxLevelName});
|
||||
if (defines.contains(minLevelName))
|
||||
this->pokemonMinLevel = defines.value(minLevelName);
|
||||
if (defines.contains(maxLevelName))
|
||||
this->pokemonMaxLevel = defines.value(maxLevelName);
|
||||
|
||||
this->pokemonMinLevel = qMin(this->pokemonMinLevel, this->pokemonMaxLevel);
|
||||
this->pokemonMaxLevel = qMax(this->pokemonMinLevel, this->pokemonMaxLevel);
|
||||
|
||||
// Read encounter data
|
||||
QString wildMonJsonFilepath = QString("%1/%2").arg(root).arg(projectConfig.getFilePath(ProjectFilePath::json_wild_encounters));
|
||||
fileWatcher.addPath(wildMonJsonFilepath);
|
||||
|
||||
|
@ -1887,19 +1972,23 @@ bool Project::readMapGroups() {
|
|||
}
|
||||
|
||||
Map* Project::addNewMapToGroup(QString mapName, int groupNum, Map *newMap, bool existingLayout, bool importedMap) {
|
||||
mapNames.append(mapName);
|
||||
mapGroups.insert(mapName, groupNum);
|
||||
groupedMapNames[groupNum].append(mapName);
|
||||
int mapNamePos = 0;
|
||||
for (int i = 0; i <= groupNum; i++)
|
||||
mapNamePos += this->groupedMapNames.value(i).length();
|
||||
|
||||
this->mapNames.insert(mapNamePos, mapName);
|
||||
this->mapGroups.insert(mapName, groupNum);
|
||||
this->groupedMapNames[groupNum].append(mapName);
|
||||
|
||||
newMap->isPersistedToFile = false;
|
||||
newMap->setName(mapName);
|
||||
|
||||
mapConstantsToMapNames.insert(newMap->constantName, newMap->name);
|
||||
mapNamesToMapConstants.insert(newMap->name, newMap->constantName);
|
||||
this->mapConstantsToMapNames.insert(newMap->constantName, newMap->name);
|
||||
this->mapNamesToMapConstants.insert(newMap->name, newMap->constantName);
|
||||
if (!existingLayout) {
|
||||
mapLayouts.insert(newMap->layoutId, newMap->layout);
|
||||
mapLayoutsTable.append(newMap->layoutId);
|
||||
layoutIdsToNames.insert(newMap->layout->id, newMap->layout->name);
|
||||
this->mapLayouts.insert(newMap->layoutId, newMap->layout);
|
||||
this->mapLayoutsTable.append(newMap->layoutId);
|
||||
this->layoutIdsToNames.insert(newMap->layout->id, newMap->layout->name);
|
||||
if (!importedMap) {
|
||||
setNewLayoutBlockdata(newMap->layout);
|
||||
}
|
||||
|
@ -1910,7 +1999,6 @@ Map* Project::addNewMapToGroup(QString mapName, int groupNum, Map *newMap, bool
|
|||
|
||||
loadLayoutTilesets(newMap->layout);
|
||||
setNewMapEvents(newMap);
|
||||
setNewMapConnections(newMap);
|
||||
|
||||
return newMap;
|
||||
}
|
||||
|
@ -1939,7 +2027,7 @@ Project::DataQualifiers Project::getDataQualifiers(QString text, QString label)
|
|||
}
|
||||
|
||||
QString Project::getDefaultPrimaryTilesetLabel() {
|
||||
QString defaultLabel = projectConfig.getDefaultPrimaryTileset();
|
||||
QString defaultLabel = projectConfig.defaultPrimaryTileset;
|
||||
if (!this->primaryTilesetLabels.contains(defaultLabel)) {
|
||||
QString firstLabel = this->primaryTilesetLabels.first();
|
||||
logWarn(QString("Unable to find default primary tileset '%1', using '%2' instead.").arg(defaultLabel).arg(firstLabel));
|
||||
|
@ -1949,7 +2037,7 @@ QString Project::getDefaultPrimaryTilesetLabel() {
|
|||
}
|
||||
|
||||
QString Project::getDefaultSecondaryTilesetLabel() {
|
||||
QString defaultLabel = projectConfig.getDefaultSecondaryTileset();
|
||||
QString defaultLabel = projectConfig.defaultSecondaryTileset;
|
||||
if (!this->secondaryTilesetLabels.contains(defaultLabel)) {
|
||||
QString firstLabel = this->secondaryTilesetLabels.first();
|
||||
logWarn(QString("Unable to find default secondary tileset '%1', using '%2' instead.").arg(defaultLabel).arg(firstLabel));
|
||||
|
@ -2027,6 +2115,7 @@ bool Project::readFieldmapProperties() {
|
|||
const QString numPalsPrimaryName = projectConfig.getIdentifier(ProjectIdentifier::define_pals_primary);
|
||||
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 QStringList names = {
|
||||
numTilesPrimaryName,
|
||||
numTilesTotalName,
|
||||
|
@ -2034,6 +2123,7 @@ bool Project::readFieldmapProperties() {
|
|||
numPalsPrimaryName,
|
||||
numPalsTotalName,
|
||||
maxMapSizeName,
|
||||
numTilesPerMetatileName,
|
||||
};
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
|
@ -2074,6 +2164,22 @@ bool Project::readFieldmapProperties() {
|
|||
.arg(Project::max_map_data_size));
|
||||
}
|
||||
|
||||
it = defines.find(numTilesPerMetatileName);
|
||||
if (it != defines.end()) {
|
||||
// We can determine whether triple-layer metatiles are in-use by reading this constant.
|
||||
// If the constant is missing (or is using a value other than 8 or 12) the user must tell
|
||||
// us whether they're using triple-layer metatiles under Project Settings.
|
||||
static const int numTilesPerLayer = 4;
|
||||
int numTilesPerMetatile = it.value();
|
||||
if (numTilesPerMetatile == 2 * numTilesPerLayer) {
|
||||
projectConfig.tripleLayerMetatilesEnabled = false;
|
||||
this->disabledSettingsNames.insert(numTilesPerMetatileName);
|
||||
} else if (numTilesPerMetatile == 3 * numTilesPerLayer) {
|
||||
projectConfig.tripleLayerMetatilesEnabled = true;
|
||||
this->disabledSettingsNames.insert(numTilesPerMetatileName);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2099,10 +2205,8 @@ bool Project::readFieldmapMasks() {
|
|||
// If users do have the defines we disable them in the settings editor and direct them to their project files.
|
||||
// Record the names we read so we know later which settings to disable.
|
||||
const QStringList defineNames = defines.keys();
|
||||
this->disabledSettingsNames = QSet<QString>(defineNames.constBegin(), defineNames.constEnd());
|
||||
|
||||
// Avoid repeatedly writing the config file
|
||||
projectConfig.setSaveDisabled(true);
|
||||
for (auto name : defineNames)
|
||||
this->disabledSettingsNames.insert(name);
|
||||
|
||||
// Read Block masks
|
||||
auto readBlockMask = [defines](const QString name, uint16_t *value) {
|
||||
|
@ -2118,21 +2222,22 @@ bool Project::readFieldmapMasks() {
|
|||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
uint16_t blockMask;
|
||||
if (readBlockMask(metatileIdMaskName, &blockMask))
|
||||
projectConfig.setBlockMetatileIdMask(blockMask);
|
||||
projectConfig.blockMetatileIdMask = blockMask;
|
||||
if (readBlockMask(collisionMaskName, &blockMask))
|
||||
projectConfig.setBlockCollisionMask(blockMask);
|
||||
projectConfig.blockCollisionMask = blockMask;
|
||||
if (readBlockMask(elevationMaskName, &blockMask))
|
||||
projectConfig.setBlockElevationMask(blockMask);
|
||||
projectConfig.blockElevationMask = blockMask;
|
||||
|
||||
// Read RSE metatile attribute masks
|
||||
auto it = defines.find(behaviorMaskName);
|
||||
if (it != defines.end())
|
||||
projectConfig.setMetatileBehaviorMask(static_cast<uint32_t>(it.value()));
|
||||
projectConfig.metatileBehaviorMask = static_cast<uint32_t>(it.value());
|
||||
it = defines.find(layerTypeMaskName);
|
||||
if (it != defines.end())
|
||||
projectConfig.setMetatileLayerTypeMask(static_cast<uint32_t>(it.value()));
|
||||
projectConfig.metatileLayerTypeMask = static_cast<uint32_t>(it.value());
|
||||
|
||||
// pokefirered keeps its attribute masks in a separate table, parse this too.
|
||||
const QString attrTableName = projectConfig.getIdentifier(ProjectIdentifier::symbol_attribute_table);
|
||||
|
@ -2149,13 +2254,13 @@ bool Project::readFieldmapMasks() {
|
|||
// Read terrain type mask
|
||||
uint32_t mask = attrTable.value(terrainTypeTableName).toUInt(&ok, 0);
|
||||
if (ok) {
|
||||
projectConfig.setMetatileTerrainTypeMask(mask);
|
||||
projectConfig.metatileTerrainTypeMask = mask;
|
||||
this->disabledSettingsNames.insert(terrainTypeTableName);
|
||||
}
|
||||
// Read encounter type mask
|
||||
mask = attrTable.value(encounterTypeTableName).toUInt(&ok, 0);
|
||||
if (ok) {
|
||||
projectConfig.setMetatileEncounterTypeMask(mask);
|
||||
projectConfig.metatileEncounterTypeMask = mask;
|
||||
this->disabledSettingsNames.insert(encounterTypeTableName);
|
||||
}
|
||||
// If we haven't already parsed behavior and layer type then try those too
|
||||
|
@ -2163,7 +2268,7 @@ bool Project::readFieldmapMasks() {
|
|||
// Read behavior mask
|
||||
mask = attrTable.value(behaviorTableName).toUInt(&ok, 0);
|
||||
if (ok) {
|
||||
projectConfig.setMetatileBehaviorMask(mask);
|
||||
projectConfig.metatileBehaviorMask = mask;
|
||||
this->disabledSettingsNames.insert(behaviorTableName);
|
||||
}
|
||||
}
|
||||
|
@ -2171,12 +2276,11 @@ bool Project::readFieldmapMasks() {
|
|||
// Read layer type mask
|
||||
mask = attrTable.value(layerTypeTableName).toUInt(&ok, 0);
|
||||
if (ok) {
|
||||
projectConfig.setMetatileLayerTypeMask(mask);
|
||||
projectConfig.metatileLayerTypeMask = mask;
|
||||
this->disabledSettingsNames.insert(layerTypeTableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
projectConfig.setSaveDisabled(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2265,7 +2369,7 @@ bool Project::readHealLocations() {
|
|||
static const QRegularExpression re_comments("//.*?(\r\n?|\n)|/\\*.*?\\*/", QRegularExpression::DotMatchesEverythingOption);
|
||||
text.replace(re_comments, "");
|
||||
|
||||
bool respawnEnabled = projectConfig.getHealLocationRespawnDataEnabled();
|
||||
bool respawnEnabled = projectConfig.healLocationRespawnDataEnabled;
|
||||
|
||||
// Search for the name of the main Heal Locations table
|
||||
const QRegularExpression tableNameExpr(QString("%1\\s+(?<name>[A-Za-z0-9_]+)\\[").arg(projectConfig.getIdentifier(ProjectIdentifier::symbol_heal_locations_type)));
|
||||
|
@ -2423,7 +2527,7 @@ bool Project::readWeatherNames() {
|
|||
}
|
||||
|
||||
bool Project::readCoordEventWeatherNames() {
|
||||
if (!projectConfig.getEventWeatherTriggerEnabled())
|
||||
if (!projectConfig.eventWeatherTriggerEnabled)
|
||||
return true;
|
||||
|
||||
const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_coord_event_weather)};
|
||||
|
@ -2436,7 +2540,7 @@ bool Project::readCoordEventWeatherNames() {
|
|||
}
|
||||
|
||||
bool Project::readSecretBaseIds() {
|
||||
if (!projectConfig.getEventSecretBaseEnabled())
|
||||
if (!projectConfig.eventSecretBaseEnabled)
|
||||
return true;
|
||||
|
||||
const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_secret_bases)};
|
||||
|
@ -2479,7 +2583,7 @@ bool Project::readMetatileBehaviors() {
|
|||
if (defines.isEmpty()) {
|
||||
// Not having any metatile behavior names is ok (their values will be displayed instead).
|
||||
// If the user's metatiles can have nonzero values then warn them, as they likely want names.
|
||||
if (projectConfig.getMetatileBehaviorMask())
|
||||
if (projectConfig.metatileBehaviorMask)
|
||||
logWarn(QString("Failed to read metatile behaviors from %1.").arg(filename));
|
||||
return true;
|
||||
}
|
||||
|
@ -2519,17 +2623,6 @@ bool Project::readObjEventGfxConstants() {
|
|||
}
|
||||
|
||||
bool Project::readMiscellaneousConstants() {
|
||||
miscConstants.clear();
|
||||
if (userConfig.getEncounterJsonActive()) {
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_pokemon);
|
||||
const QString minLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_min_level);
|
||||
const QString maxLevelName = projectConfig.getIdentifier(ProjectIdentifier::define_max_level);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
QMap<QString, int> pokemonDefines = parser.readCDefinesByName(filename, {minLevelName, maxLevelName});
|
||||
miscConstants.insert("max_level_define", pokemonDefines.value(maxLevelName) > pokemonDefines.value(minLevelName) ? pokemonDefines.value(maxLevelName) : 100);
|
||||
miscConstants.insert("min_level_define", pokemonDefines.value(minLevelName) < pokemonDefines.value(maxLevelName) ? pokemonDefines.value(minLevelName) : 1);
|
||||
}
|
||||
|
||||
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_global);
|
||||
const QString maxObjectEventsName = projectConfig.getIdentifier(ProjectIdentifier::define_obj_event_count);
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
|
@ -2599,9 +2692,8 @@ QStringList Project::getEventScriptsFilePaths() const {
|
|||
QStringList filePaths(QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_event_scripts)));
|
||||
const QString scriptsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_scripts_folders));
|
||||
const QString mapsDir = QDir::cleanPath(root + "/" + projectConfig.getFilePath(ProjectFilePath::data_map_folders));
|
||||
const bool usePoryscript = projectConfig.getUsePoryScript();
|
||||
|
||||
if (usePoryscript) {
|
||||
if (projectConfig.usePoryScript) {
|
||||
QDirIterator it_pory_shared(scriptsDir, {"*.pory"}, QDir::Files);
|
||||
while (it_pory_shared.hasNext())
|
||||
filePaths << it_pory_shared.next();
|
||||
|
@ -2719,7 +2811,7 @@ bool Project::readSpeciesIconPaths() {
|
|||
const QMap<QString, QString> iconIncbins = parser.readCIncbinMulti(incfilename);
|
||||
|
||||
// Read species constants. If this fails we can get them from the icon table (but we shouldn't rely on it).
|
||||
const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_species)};
|
||||
const QStringList prefixes = {QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix))};
|
||||
const QString constantsFilename = projectConfig.getFilePath(ProjectFilePath::constants_species);
|
||||
fileWatcher.addPath(root + "/" + constantsFilename);
|
||||
QStringList speciesNames = parser.readCDefineNames(constantsFilename, prefixes);
|
||||
|
@ -2902,7 +2994,7 @@ QString Project::getExistingFilepath(QString filepath) {
|
|||
if (filepath.isEmpty() || QFile::exists(filepath))
|
||||
return filepath;
|
||||
|
||||
filepath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + filepath);
|
||||
filepath = QDir::cleanPath(projectConfig.projectDir + QDir::separator() + filepath);
|
||||
if (QFile::exists(filepath))
|
||||
return filepath;
|
||||
|
||||
|
@ -2915,25 +3007,19 @@ QString Project::getExistingFilepath(QString filepath) {
|
|||
// can be limited by fieldmap defines)
|
||||
// Once we've read data from the project files we can adjust these accordingly.
|
||||
void Project::applyParsedLimits() {
|
||||
// Avoid repeatedly writing the config file
|
||||
projectConfig.setSaveDisabled(true);
|
||||
|
||||
uint32_t maxMask = Metatile::getMaxAttributesMask();
|
||||
projectConfig.setMetatileBehaviorMask(projectConfig.getMetatileBehaviorMask() & maxMask);
|
||||
projectConfig.setMetatileTerrainTypeMask(projectConfig.getMetatileTerrainTypeMask() & maxMask);
|
||||
projectConfig.setMetatileEncounterTypeMask(projectConfig.getMetatileEncounterTypeMask() & maxMask);
|
||||
projectConfig.setMetatileLayerTypeMask(projectConfig.getMetatileLayerTypeMask() & maxMask);
|
||||
projectConfig.metatileBehaviorMask &= maxMask;
|
||||
projectConfig.metatileTerrainTypeMask &= maxMask;
|
||||
projectConfig.metatileEncounterTypeMask &= maxMask;
|
||||
projectConfig.metatileLayerTypeMask &= maxMask;
|
||||
|
||||
Block::setLayout();
|
||||
Metatile::setLayout(this);
|
||||
|
||||
Project::num_metatiles_primary = qMin(Project::num_metatiles_primary, Block::getMaxMetatileId() + 1);
|
||||
projectConfig.setDefaultMetatileId(qMin(projectConfig.getDefaultMetatileId(), Block::getMaxMetatileId()));
|
||||
projectConfig.setDefaultElevation(qMin(projectConfig.getDefaultElevation(), Block::getMaxElevation()));
|
||||
projectConfig.setDefaultCollision(qMin(projectConfig.getDefaultCollision(), Block::getMaxCollision()));
|
||||
projectConfig.setCollisionSheetHeight(qMin(projectConfig.getCollisionSheetHeight(), Block::getMaxElevation() + 1));
|
||||
projectConfig.setCollisionSheetWidth(qMin(projectConfig.getCollisionSheetWidth(), Block::getMaxCollision() + 1));
|
||||
|
||||
projectConfig.setSaveDisabled(false);
|
||||
projectConfig.save();
|
||||
projectConfig.defaultMetatileId = qMin(projectConfig.defaultMetatileId, Block::getMaxMetatileId());
|
||||
projectConfig.defaultElevation = qMin(projectConfig.defaultElevation, Block::getMaxElevation());
|
||||
projectConfig.defaultCollision = qMin(projectConfig.defaultCollision, Block::getMaxCollision());
|
||||
projectConfig.collisionSheetHeight = qMin(projectConfig.collisionSheetHeight, Block::getMaxElevation() + 1);
|
||||
projectConfig.collisionSheetWidth = qMin(projectConfig.collisionSheetWidth, Block::getMaxCollision() + 1);
|
||||
}
|
||||
|
|
|
@ -295,7 +295,7 @@ int MainWindow::getBorderHeight() {
|
|||
}
|
||||
|
||||
void MainWindow::setBorderDimensions(int width, int height) {
|
||||
if (!this->editor || !this->editor->layout || !projectConfig.getUseCustomBorderSize())
|
||||
if (!this->editor || !this->editor->layout || !projectConfig.useCustomBorderSize)
|
||||
return;
|
||||
if (width < 1 || height < 1 || width > MAX_BORDER_WIDTH || height > MAX_BORDER_HEIGHT)
|
||||
return;
|
||||
|
@ -305,7 +305,7 @@ void MainWindow::setBorderDimensions(int width, int height) {
|
|||
}
|
||||
|
||||
void MainWindow::setBorderWidth(int width) {
|
||||
if (!this->editor || !this->editor->layout || !projectConfig.getUseCustomBorderSize())
|
||||
if (!this->editor || !this->editor->layout || !projectConfig.useCustomBorderSize)
|
||||
return;
|
||||
if (width < 1 || width > MAX_BORDER_WIDTH)
|
||||
return;
|
||||
|
@ -315,7 +315,7 @@ void MainWindow::setBorderWidth(int width) {
|
|||
}
|
||||
|
||||
void MainWindow::setBorderHeight(int height) {
|
||||
if (!this->editor || !this->editor->layout || !projectConfig.getUseCustomBorderSize())
|
||||
if (!this->editor || !this->editor->layout || !projectConfig.useCustomBorderSize)
|
||||
return;
|
||||
if (height < 1 || height > MAX_BORDER_HEIGHT)
|
||||
return;
|
||||
|
|
|
@ -7,6 +7,18 @@ ScriptUtility::ScriptUtility(MainWindow *mainWindow) {
|
|||
this->window = mainWindow;
|
||||
}
|
||||
|
||||
ScriptUtility::~ScriptUtility() {
|
||||
if (window && window->ui && window->ui->menuTools) {
|
||||
for (auto action : this->registeredActions) {
|
||||
window->ui->menuTools->removeAction(action);
|
||||
}
|
||||
}
|
||||
for (auto timer : this->activeTimers) {
|
||||
timer->stop();
|
||||
delete timer;
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptUtility::registerAction(QString functionName, QString actionName, QString shortcut) {
|
||||
if (!window || !window->ui || !window->ui->menuTools)
|
||||
return false;
|
||||
|
@ -44,12 +56,6 @@ bool ScriptUtility::registerToggleAction(QString functionName, QString actionNam
|
|||
return true;
|
||||
}
|
||||
|
||||
void ScriptUtility::clearActions() {
|
||||
for (auto action : this->registeredActions) {
|
||||
window->ui->menuTools->removeAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
QString ScriptUtility::getActionFunctionName(int actionIndex) {
|
||||
return this->actionMap.value(actionIndex);
|
||||
}
|
||||
|
@ -58,11 +64,15 @@ void ScriptUtility::setTimeout(QJSValue callback, int milliseconds) {
|
|||
if (!callback.isCallable() || milliseconds < 0)
|
||||
return;
|
||||
|
||||
QTimer *timer = new QTimer(0);
|
||||
QTimer *timer = new QTimer();
|
||||
connect(timer, &QTimer::timeout, [=](){
|
||||
this->callTimeoutFunction(callback);
|
||||
if (this->activeTimers.remove(timer)) {
|
||||
this->callTimeoutFunction(callback);
|
||||
timer->deleteLater();
|
||||
}
|
||||
});
|
||||
connect(timer, &QTimer::timeout, timer, &QTimer::deleteLater);
|
||||
|
||||
this->activeTimers.insert(timer);
|
||||
timer->setSingleShot(true);
|
||||
timer->start(milliseconds);
|
||||
}
|
||||
|
@ -157,7 +167,10 @@ int ScriptUtility::getMapViewTab() {
|
|||
}
|
||||
|
||||
void ScriptUtility::setMapViewTab(int index) {
|
||||
if (this->getMainTab() != 0 || !window->ui->mapViewTab || index < 0 || index >= window->ui->mapViewTab->count())
|
||||
if (this->getMainTab() != MainTab::Map || !window->ui->mapViewTab || index < 0 || index >= window->ui->mapViewTab->count())
|
||||
return;
|
||||
// Can't select tab if it's disabled
|
||||
if (!window->ui->mapViewTab->isTabEnabled(index))
|
||||
return;
|
||||
window->on_mapViewTab_tabBarClicked(index);
|
||||
}
|
||||
|
@ -171,7 +184,7 @@ bool ScriptUtility::getGridVisibility() {
|
|||
}
|
||||
|
||||
void ScriptUtility::setBorderVisibility(bool visible) {
|
||||
window->editor->toggleBorderVisibility(visible, false);
|
||||
window->ui->checkBox_ToggleBorder->setChecked(visible);
|
||||
}
|
||||
|
||||
bool ScriptUtility::getBorderVisibility() {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include <QQmlEngine>
|
||||
|
||||
#include "scripting.h"
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
|
||||
QMap<CallbackType, QString> callbackFunctions = {
|
||||
const QMap<CallbackType, QString> callbackFunctions = {
|
||||
{OnProjectOpened, "onProjectOpened"},
|
||||
{OnProjectClosed, "onProjectClosed"},
|
||||
{OnBlockChanged, "onBlockChanged"},
|
||||
|
@ -21,20 +23,21 @@ QMap<CallbackType, QString> callbackFunctions = {
|
|||
|
||||
Scripting *instance = nullptr;
|
||||
|
||||
void Scripting::stop() {
|
||||
delete instance;
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
void Scripting::init(MainWindow *mainWindow) {
|
||||
mainWindow->ui->graphicsView_Map->clearOverlayMap();
|
||||
if (instance) {
|
||||
instance->engine->setInterrupted(true);
|
||||
instance->scriptUtility->clearActions();
|
||||
qDeleteAll(instance->imageCache);
|
||||
delete instance;
|
||||
}
|
||||
if (mainWindow->ui->graphicsView_Map)
|
||||
mainWindow->ui->graphicsView_Map->clearOverlayMap();
|
||||
Scripting::stop();
|
||||
instance = new Scripting(mainWindow);
|
||||
}
|
||||
|
||||
Scripting::Scripting(MainWindow *mainWindow) {
|
||||
this->mainWindow = mainWindow;
|
||||
this->engine = new QJSEngine(mainWindow);
|
||||
this->engine = new QJSEngine();
|
||||
this->engine->installExtensions(QJSEngine::ConsoleExtension);
|
||||
const QStringList paths = userConfig.getCustomScriptPaths();
|
||||
const QList<bool> enabled = userConfig.getCustomScriptsEnabled();
|
||||
|
@ -46,6 +49,13 @@ Scripting::Scripting(MainWindow *mainWindow) {
|
|||
this->scriptUtility = new ScriptUtility(mainWindow);
|
||||
}
|
||||
|
||||
Scripting::~Scripting() {
|
||||
this->engine->setInterrupted(true);
|
||||
qDeleteAll(this->imageCache);
|
||||
delete this->engine;
|
||||
delete this->scriptUtility;
|
||||
}
|
||||
|
||||
void Scripting::loadModules(QStringList moduleFiles) {
|
||||
for (QString filepath : moduleFiles) {
|
||||
QString validPath = Project::getExistingFilepath(filepath);
|
||||
|
@ -74,6 +84,11 @@ void Scripting::populateGlobalObject(MainWindow *mainWindow) {
|
|||
instance->engine->globalObject().setProperty("overlay", instance->engine->newQObject(mainWindow->ui->graphicsView_Map));
|
||||
instance->engine->globalObject().setProperty("utility", instance->engine->newQObject(instance->scriptUtility));
|
||||
|
||||
// Note: QJSEngine also has these functions, but not in Qt 5.15.
|
||||
QQmlEngine::setObjectOwnership(mainWindow, QQmlEngine::CppOwnership);
|
||||
QQmlEngine::setObjectOwnership(mainWindow->ui->graphicsView_Map, QQmlEngine::CppOwnership);
|
||||
QQmlEngine::setObjectOwnership(instance->scriptUtility, QQmlEngine::CppOwnership);
|
||||
|
||||
QJSValue constants = instance->engine->newObject();
|
||||
|
||||
// Get version numbers
|
||||
|
|
|
@ -7,6 +7,7 @@ AboutPorymap::AboutPorymap(QWidget *parent) :
|
|||
ui(new Ui::AboutPorymap)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
this->ui->label_Version->setText(QString("Version %1 - %2").arg(QCoreApplication::applicationVersion()).arg(QStringLiteral(__DATE__)));
|
||||
this->ui->textBrowser->setSource(QUrl("qrc:/CHANGELOG.md"));
|
||||
|
|
|
@ -15,7 +15,7 @@ void CityMapPixmapItem::init() {
|
|||
if (!binFile.open(QIODevice::ReadOnly)) return;
|
||||
|
||||
data = binFile.readAll();
|
||||
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) {
|
||||
if (projectConfig.baseGameVersion == BaseGameVersion::pokeruby) {
|
||||
for (int i = 0; i < data.size(); i++)
|
||||
data[i] = data[i] ^ 0x80;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ void CityMapPixmapItem::save() {
|
|||
logError(QString("Cannot save city map tilemap to %1.").arg(file));
|
||||
return;
|
||||
}
|
||||
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) {
|
||||
if (projectConfig.baseGameVersion == BaseGameVersion::pokeruby) {
|
||||
for (int i = 0; i < data.size(); i++)
|
||||
data[i] = data[i] ^ 0x80;
|
||||
}
|
||||
|
|
|
@ -1,30 +1,48 @@
|
|||
#include "connectionpixmapitem.h"
|
||||
#include "editcommands.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
void ConnectionPixmapItem::render(qreal opacity) {
|
||||
QPixmap newPixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
|
||||
if (opacity < 1) {
|
||||
QPainter painter(&newPixmap);
|
||||
int alpha = static_cast<int>(255 * (1 - opacity));
|
||||
painter.fillRect(0, 0, newPixmap.width(), newPixmap.height(), QColor(0, 0, 0, alpha));
|
||||
painter.end();
|
||||
ConnectionPixmapItem::ConnectionPixmapItem(MapConnection* connection, int x, int y)
|
||||
: QGraphicsPixmapItem(connection->getPixmap()),
|
||||
connection(connection)
|
||||
{
|
||||
this->setEditable(true);
|
||||
this->basePixmap = pixmap();
|
||||
this->setOrigin(x, y);
|
||||
}
|
||||
|
||||
ConnectionPixmapItem::ConnectionPixmapItem(MapConnection* connection, QPoint pos)
|
||||
: ConnectionPixmapItem(connection, pos.x(), pos.y())
|
||||
{}
|
||||
|
||||
// Render additional visual effects on top of the base map image.
|
||||
void ConnectionPixmapItem::render(bool ignoreCache) {
|
||||
if (ignoreCache)
|
||||
this->basePixmap = this->connection->getPixmap();
|
||||
|
||||
QPixmap pixmap = this->basePixmap.copy(0, 0, this->basePixmap.width(), this->basePixmap.height());
|
||||
this->setZValue(-1);
|
||||
|
||||
// When editing is inactive the current selection is ignored, all connections should appear normal.
|
||||
if (this->getEditable()) {
|
||||
if (this->selected) {
|
||||
// Draw highlight
|
||||
QPainter painter(&pixmap);
|
||||
painter.setPen(QColor(255, 0, 255));
|
||||
painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1);
|
||||
painter.end();
|
||||
} else {
|
||||
// Darken the image
|
||||
this->setZValue(-2);
|
||||
QPainter painter(&pixmap);
|
||||
int alpha = static_cast<int>(255 * 0.25);
|
||||
painter.fillRect(0, 0, pixmap.width(), pixmap.height(), QColor(0, 0, 0, alpha));
|
||||
painter.end();
|
||||
}
|
||||
}
|
||||
this->setPixmap(newPixmap);
|
||||
}
|
||||
|
||||
int ConnectionPixmapItem::getMinOffset() {
|
||||
if (this->connection->direction == "up" || this->connection->direction == "down")
|
||||
return -(this->pixmap().width() / 16) - 6;
|
||||
else
|
||||
return -(this->pixmap().height() / 16) - 6;
|
||||
}
|
||||
|
||||
int ConnectionPixmapItem::getMaxOffset() {
|
||||
if (this->connection->direction == "up" || this->connection->direction == "down")
|
||||
return this->baseMapWidth + 6;
|
||||
else
|
||||
return this->baseMapHeight + 6;
|
||||
this->setPixmap(pixmap);
|
||||
}
|
||||
|
||||
QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
|
@ -32,32 +50,23 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
|
|||
if (change == ItemPositionChange) {
|
||||
QPointF newPos = value.toPointF();
|
||||
|
||||
qreal x, y;
|
||||
int newOffset = this->initialOffset;
|
||||
if (this->connection->direction == "up" || this->connection->direction == "down") {
|
||||
x = round(newPos.x() / 16) * 16;
|
||||
newOffset += (x - initialX) / 16;
|
||||
newOffset = qMin(newOffset, this->getMaxOffset());
|
||||
newOffset = qMax(newOffset, this->getMinOffset());
|
||||
x = newOffset * 16;
|
||||
}
|
||||
else {
|
||||
x = this->initialX;
|
||||
qreal x = this->originX;
|
||||
qreal y = this->originY;
|
||||
int newOffset = this->connection->offset();
|
||||
|
||||
// Restrict movement to the metatile grid and perpendicular to the connection direction.
|
||||
if (MapConnection::isVertical(this->connection->direction())) {
|
||||
x = (round(newPos.x() / this->mWidth) * this->mWidth) - this->originX;
|
||||
newOffset = x / this->mWidth;
|
||||
} else if (MapConnection::isHorizontal(this->connection->direction())) {
|
||||
y = (round(newPos.y() / this->mHeight) * this->mHeight) - this->originY;
|
||||
newOffset = y / this->mHeight;
|
||||
}
|
||||
|
||||
if (this->connection->direction == "right" || this->connection->direction == "left") {
|
||||
y = round(newPos.y() / 16) * 16;
|
||||
newOffset += (y - this->initialY) / 16;
|
||||
newOffset = qMin(newOffset, this->getMaxOffset());
|
||||
newOffset = qMax(newOffset, this->getMinOffset());
|
||||
y = newOffset * 16;
|
||||
}
|
||||
else {
|
||||
y = this->initialY;
|
||||
}
|
||||
// This is convoluted because of how our edit history works; this would otherwise just be 'this->connection->setOffset(newOffset);'
|
||||
if (this->connection->parentMap() && newOffset != this->connection->offset())
|
||||
this->connection->parentMap()->editHistory.push(new MapConnectionMove(this->connection, newOffset, this->actionId));
|
||||
|
||||
this->connection->offset = newOffset;
|
||||
emit connectionMoved(this->connection);
|
||||
return QPointF(x, y);
|
||||
}
|
||||
else {
|
||||
|
@ -65,6 +74,32 @@ QVariant ConnectionPixmapItem::itemChange(GraphicsItemChange change, const QVari
|
|||
}
|
||||
}
|
||||
|
||||
// If connection->offset changed externally we call this to correct our position.
|
||||
void ConnectionPixmapItem::updatePos() {
|
||||
const QSignalBlocker blocker(this);
|
||||
|
||||
qreal x = this->originX;
|
||||
qreal y = this->originY;
|
||||
|
||||
if (MapConnection::isVertical(this->connection->direction())) {
|
||||
x += this->connection->offset() * this->mWidth;
|
||||
} else if (MapConnection::isHorizontal(this->connection->direction())) {
|
||||
y += this->connection->offset() * this->mHeight;
|
||||
}
|
||||
|
||||
this->setPos(x, y);
|
||||
}
|
||||
|
||||
// Set the pixmap's external origin point, i.e. the pixmap's position when connection->offset == 0
|
||||
void ConnectionPixmapItem::setOrigin(int x, int y) {
|
||||
this->originX = x;
|
||||
this->originY = y;
|
||||
updatePos();
|
||||
}
|
||||
void ConnectionPixmapItem::setOrigin(QPoint pos) {
|
||||
this->setOrigin(pos.x(), pos.y());
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::setEditable(bool editable) {
|
||||
setFlag(ItemIsMovable, editable);
|
||||
setFlag(ItemSendsGeometryChanges, editable);
|
||||
|
@ -74,28 +109,25 @@ bool ConnectionPixmapItem::getEditable() {
|
|||
return (this->flags() & ItemIsMovable) != 0;
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::updateHighlight(bool selected) {
|
||||
bool editable = this->getEditable();
|
||||
int zValue = (selected || !editable) ? -1 : -2;
|
||||
qreal opacity = (selected || !editable) ? 1 : 0.75;
|
||||
this->setZValue(zValue);
|
||||
this->render(opacity);
|
||||
if (editable && selected) {
|
||||
QPixmap pixmap = this->pixmap();
|
||||
QPainter painter(&pixmap);
|
||||
painter.setPen(QColor(255, 0, 255));
|
||||
painter.drawRect(0, 0, pixmap.width() - 1, pixmap.height() - 1);
|
||||
painter.end();
|
||||
this->setPixmap(pixmap);
|
||||
}
|
||||
void ConnectionPixmapItem::setSelected(bool selected) {
|
||||
if (this->selected == selected)
|
||||
return;
|
||||
this->selected = selected;
|
||||
this->render();
|
||||
emit selectionChanged(selected);
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *) {
|
||||
if (!this->getEditable())
|
||||
return;
|
||||
emit connectionItemSelected(this);
|
||||
this->setSelected(true);
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
||||
this->actionId++; // Distinguish between move actions for the edit history
|
||||
QGraphicsPixmapItem::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void ConnectionPixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
|
||||
emit connectionItemDoubleClicked(this);
|
||||
emit connectionItemDoubleClicked(this->connection);
|
||||
}
|
||||
|
|
103
src/ui/connectionslistitem.cpp
Normal file
103
src/ui/connectionslistitem.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include "connectionslistitem.h"
|
||||
#include "ui_connectionslistitem.h"
|
||||
#include "editcommands.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
ConnectionsListItem::ConnectionsListItem(QWidget *parent, MapConnection * connection, const QStringList &mapNames) :
|
||||
QFrame(parent),
|
||||
ui(new Ui::ConnectionsListItem)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
const QSignalBlocker blocker1(ui->comboBox_Direction);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Map);
|
||||
const QSignalBlocker blocker3(ui->spinBox_Offset);
|
||||
|
||||
ui->comboBox_Direction->setEditable(false);
|
||||
ui->comboBox_Direction->setMinimumContentsLength(0);
|
||||
ui->comboBox_Direction->addItems(MapConnection::cardinalDirections);
|
||||
|
||||
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->spinBox_Offset->setMinimum(INT_MIN);
|
||||
ui->spinBox_Offset->setMaximum(INT_MAX);
|
||||
|
||||
// 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)
|
||||
ui->comboBox_Map->setTextItem(this->connection->targetMapName());
|
||||
});
|
||||
|
||||
// Distinguish between move actions for the edit history
|
||||
connect(ui->spinBox_Offset, &QSpinBox::editingFinished, [this] { this->actionId++; });
|
||||
|
||||
this->connection = connection;
|
||||
this->map = connection->parentMap();
|
||||
this->updateUI();
|
||||
}
|
||||
|
||||
ConnectionsListItem::~ConnectionsListItem()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConnectionsListItem::updateUI() {
|
||||
if (!this->connection)
|
||||
return;
|
||||
|
||||
const QSignalBlocker blocker1(ui->comboBox_Direction);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Map);
|
||||
const QSignalBlocker blocker3(ui->spinBox_Offset);
|
||||
|
||||
ui->comboBox_Direction->setTextItem(this->connection->direction());
|
||||
ui->comboBox_Map->setTextItem(this->connection->targetMapName());
|
||||
ui->spinBox_Offset->setValue(this->connection->offset());
|
||||
}
|
||||
|
||||
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; }");
|
||||
if (selected)
|
||||
emit this->selected();
|
||||
}
|
||||
|
||||
void ConnectionsListItem::mousePressEvent(QMouseEvent *) {
|
||||
this->setSelected(true);
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_comboBox_Direction_currentTextChanged(QString direction) {
|
||||
this->setSelected(true);
|
||||
if (this->map)
|
||||
this->map->editHistory.push(new MapConnectionChangeDirection(this->connection, direction));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_comboBox_Map_currentTextChanged(QString mapName) {
|
||||
this->setSelected(true);
|
||||
if (this->map && ui->comboBox_Map->findText(mapName) >= 0)
|
||||
this->map->editHistory.push(new MapConnectionChangeMap(this->connection, mapName));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_spinBox_Offset_valueChanged(int offset) {
|
||||
this->setSelected(true);
|
||||
if (this->map)
|
||||
this->map->editHistory.push(new MapConnectionMove(this->connection, offset, this->actionId));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_button_Delete_clicked() {
|
||||
if (this->map)
|
||||
this->map->editHistory.push(new MapConnectionRemove(this->map, this->connection));
|
||||
}
|
||||
|
||||
void ConnectionsListItem::on_button_OpenMap_clicked() {
|
||||
emit openMapClicked(this->connection);
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
CustomScriptsEditor::CustomScriptsEditor(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::CustomScriptsEditor),
|
||||
baseDir(userConfig.getProjectDir() + QDir::separator())
|
||||
baseDir(userConfig.projectDir + QDir::separator())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
@ -23,11 +23,11 @@ CustomScriptsEditor::CustomScriptsEditor(QWidget *parent) :
|
|||
for (int i = 0; i < paths.length(); i++)
|
||||
this->displayScript(paths.at(i), enabled.at(i));
|
||||
|
||||
this->fileDialogDir = userConfig.getProjectDir();
|
||||
this->fileDialogDir = userConfig.projectDir;
|
||||
|
||||
connect(ui->button_CreateNewScript, &QAbstractButton::clicked, this, &CustomScriptsEditor::createNewScript);
|
||||
connect(ui->button_LoadScript, &QAbstractButton::clicked, this, &CustomScriptsEditor::loadScript);
|
||||
connect(ui->button_RefreshScripts, &QAbstractButton::clicked, this, &CustomScriptsEditor::refreshScripts);
|
||||
connect(ui->button_RefreshScripts, &QAbstractButton::clicked, this, &CustomScriptsEditor::userRefreshScripts);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &CustomScriptsEditor::dialogButtonClicked);
|
||||
|
||||
this->initShortcuts();
|
||||
|
@ -57,7 +57,7 @@ void CustomScriptsEditor::initShortcuts() {
|
|||
shortcut_load->setObjectName("shortcut_load");
|
||||
shortcut_load->setWhatsThis("Load Script...");
|
||||
|
||||
auto *shortcut_refresh = new Shortcut(QKeySequence(), this, SLOT(refreshScripts()));
|
||||
auto *shortcut_refresh = new Shortcut(QKeySequence(), this, SLOT(userRefreshScripts()));
|
||||
shortcut_refresh->setObjectName("shortcut_refresh");
|
||||
shortcut_refresh->setWhatsThis("Refresh Scripts");
|
||||
|
||||
|
@ -238,14 +238,21 @@ void CustomScriptsEditor::openSelectedScripts() {
|
|||
this->openScript(item);
|
||||
}
|
||||
|
||||
void CustomScriptsEditor::refreshScripts() {
|
||||
// When the user refreshes the scripts we show a little tooltip as feedback.
|
||||
// We don't want this tooltip to display when we refresh programmatically, like when changes are saved.
|
||||
void CustomScriptsEditor::userRefreshScripts() {
|
||||
if (refreshScripts())
|
||||
QToolTip::showText(ui->button_RefreshScripts->mapToGlobal(QPoint(0, 0)), "Refreshed!");
|
||||
}
|
||||
|
||||
bool CustomScriptsEditor::refreshScripts() {
|
||||
if (this->hasUnsavedChanges) {
|
||||
if (this->prompt("Scripts have been modified, save changes and reload the script engine?", QMessageBox::Yes) == QMessageBox::No)
|
||||
return;
|
||||
return false;
|
||||
this->save();
|
||||
}
|
||||
QToolTip::showText(ui->button_RefreshScripts->mapToGlobal(QPoint(0, 0)), "Refreshed!");
|
||||
emit reloadScriptEngine();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CustomScriptsEditor::save() {
|
||||
|
@ -264,6 +271,7 @@ void CustomScriptsEditor::save() {
|
|||
}
|
||||
|
||||
userConfig.setCustomScripts(paths, enabledStates);
|
||||
userConfig.save();
|
||||
this->hasUnsavedChanges = false;
|
||||
this->refreshScripts();
|
||||
}
|
||||
|
|
46
src/ui/divingmappixmapitem.cpp
Normal file
46
src/ui/divingmappixmapitem.cpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#include "divingmappixmapitem.h"
|
||||
#include "config.h"
|
||||
|
||||
DivingMapPixmapItem::DivingMapPixmapItem(MapConnection *connection, QComboBox *combo)
|
||||
: QGraphicsPixmapItem(getBasePixmap(connection))
|
||||
{
|
||||
m_connection = connection;
|
||||
m_combo = combo;
|
||||
|
||||
setComboText(connection->targetMapName());
|
||||
|
||||
// Update display if the connected map is swapped.
|
||||
connect(m_connection, &MapConnection::targetMapNameChanged, this, &DivingMapPixmapItem::onTargetMapChanged);
|
||||
}
|
||||
|
||||
DivingMapPixmapItem::~DivingMapPixmapItem() {
|
||||
// Clear map name from combo box
|
||||
setComboText("");
|
||||
}
|
||||
|
||||
QPixmap DivingMapPixmapItem::getBasePixmap(MapConnection* connection) {
|
||||
if (!connection)
|
||||
return QPixmap();
|
||||
if (!porymapConfig.showDiveEmergeMaps)
|
||||
return QPixmap(); // Save some rendering time if it won't be displayed
|
||||
if (connection->targetMapName() == connection->parentMapName())
|
||||
return QPixmap(); // If the map is connected to itself then rendering is pointless.
|
||||
return connection->getPixmap();
|
||||
}
|
||||
|
||||
void DivingMapPixmapItem::updatePixmap() {
|
||||
setPixmap(getBasePixmap(m_connection));
|
||||
}
|
||||
|
||||
void DivingMapPixmapItem::onTargetMapChanged() {
|
||||
updatePixmap();
|
||||
setComboText(m_connection->targetMapName());
|
||||
}
|
||||
|
||||
void DivingMapPixmapItem::setComboText(const QString &text) {
|
||||
if (!m_combo)
|
||||
return;
|
||||
|
||||
const QSignalBlocker blocker(m_combo);
|
||||
m_combo->setCurrentText(text);
|
||||
}
|
|
@ -34,11 +34,26 @@ void DraggablePixmapItem::updatePixmap() {
|
|||
}
|
||||
|
||||
void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) {
|
||||
active = true;
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(mouse->scenePos());
|
||||
last_x = pos.x();
|
||||
last_y = pos.y();
|
||||
this->editor->selectMapEvent(this, mouse->modifiers() & Qt::ControlModifier);
|
||||
if (this->active)
|
||||
return;
|
||||
this->active = true;
|
||||
this->lastPos = Metatile::coordFromPixmapCoord(mouse->scenePos());
|
||||
|
||||
bool selectionToggle = mouse->modifiers() & Qt::ControlModifier;
|
||||
if (selectionToggle || !editor->selected_events->contains(this)) {
|
||||
// User is either toggling this selection on/off as part of a group selection,
|
||||
// or they're newly selecting just this item.
|
||||
this->editor->selectMapEvent(this, selectionToggle);
|
||||
} else {
|
||||
// This item is already selected and the user isn't toggling the selection, so there are 4 possibilities:
|
||||
// 1. This is the only selected event, and the selection is pointless.
|
||||
// 2. This is the only selected event, and they want to drag the item around.
|
||||
// 3. There's a group selection, and they want to start a new selection with just this item.
|
||||
// 4. There's a group selection, and they want to drag the group around.
|
||||
// 'selectMapEvent' will immediately clear the rest of the selection, which supports #1-3 but prevents #4.
|
||||
// To support #4 we set the flag below, and we only call 'selectMapEvent' on mouse release if no move occurred.
|
||||
this->releaseSelectionQueued = true;
|
||||
}
|
||||
this->editor->selectingEvent = true;
|
||||
}
|
||||
|
||||
|
@ -57,28 +72,39 @@ void DraggablePixmapItem::moveTo(const QPoint &pos) {
|
|||
}
|
||||
|
||||
void DraggablePixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *mouse) {
|
||||
if (active) {
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(mouse->scenePos());
|
||||
if (pos.x() != last_x || pos.y() != last_y) {
|
||||
emit this->editor->map_item->hoveredMapMetatileChanged(pos);
|
||||
QList <Event *> selectedEvents;
|
||||
if (editor->selected_events->contains(this)) {
|
||||
for (DraggablePixmapItem *item : *editor->selected_events) {
|
||||
selectedEvents.append(item->event);
|
||||
}
|
||||
} else {
|
||||
selectedEvents.append(this->event);
|
||||
}
|
||||
editor->map->editHistory.push(new EventMove(selectedEvents, pos.x() - last_x, pos.y() - last_y, currentActionId));
|
||||
last_x = pos.x();
|
||||
last_y = pos.y();
|
||||
if (!this->active)
|
||||
return;
|
||||
|
||||
QPoint pos = Metatile::coordFromPixmapCoord(mouse->scenePos());
|
||||
if (pos == this->lastPos)
|
||||
return;
|
||||
|
||||
QPoint moveDistance = pos - this->lastPos;
|
||||
this->lastPos = pos;
|
||||
emit this->editor->map_item->hoveredMapMetatileChanged(pos);
|
||||
|
||||
QList <Event *> selectedEvents;
|
||||
if (editor->selected_events->contains(this)) {
|
||||
for (DraggablePixmapItem *item : *editor->selected_events) {
|
||||
selectedEvents.append(item->event);
|
||||
}
|
||||
} else {
|
||||
selectedEvents.append(this->event);
|
||||
}
|
||||
editor->map->editHistory.push(new EventMove(selectedEvents, moveDistance.x(), moveDistance.y(), currentActionId));
|
||||
this->releaseSelectionQueued = false;
|
||||
}
|
||||
|
||||
void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) {
|
||||
active = false;
|
||||
void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouse) {
|
||||
if (!this->active)
|
||||
return;
|
||||
this->active = false;
|
||||
currentActionId++;
|
||||
if (this->releaseSelectionQueued) {
|
||||
this->releaseSelectionQueued = false;
|
||||
if (Metatile::coordFromPixmapCoord(mouse->scenePos()) == this->lastPos)
|
||||
this->editor->selectMapEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
|
||||
|
|
|
@ -50,7 +50,7 @@ QWidget *SpeciesComboDelegate::createEditor(QWidget *parent, const QStyleOptionV
|
|||
void SpeciesComboDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {
|
||||
QString species = index.data(Qt::EditRole).toString();
|
||||
NoScrollComboBox *combo = static_cast<NoScrollComboBox *>(editor);
|
||||
combo->setCurrentIndex(combo->findText(species));
|
||||
combo->setCurrentText(species);
|
||||
}
|
||||
|
||||
void SpeciesComboDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
|
||||
|
@ -75,12 +75,12 @@ QWidget *SpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewIt
|
|||
|
||||
int col = index.column();
|
||||
if (col == EncounterTableModel::ColumnType::MinLevel || col == EncounterTableModel::ColumnType::MaxLevel) {
|
||||
editor->setMinimum(this->project->miscConstants.value("min_level_define").toInt());
|
||||
editor->setMaximum(this->project->miscConstants.value("max_level_define").toInt());
|
||||
editor->setMinimum(this->project->pokemonMinLevel);
|
||||
editor->setMaximum(this->project->pokemonMaxLevel);
|
||||
}
|
||||
else if (col == EncounterTableModel::ColumnType::EncounterRate) {
|
||||
editor->setMinimum(0);
|
||||
editor->setMaximum(180);
|
||||
editor->setMaximum(this->project->maxEncounterRate);
|
||||
}
|
||||
|
||||
return editor;
|
||||
|
|
|
@ -142,45 +142,57 @@ QVariant EncounterTableModel::headerData(int section, Qt::Orientation orientatio
|
|||
}
|
||||
|
||||
bool EncounterTableModel::setData(const QModelIndex &index, const QVariant &value, int role) {
|
||||
if (role == Qt::EditRole) {
|
||||
if (!checkIndex(index))
|
||||
return false;
|
||||
if (role != Qt::EditRole)
|
||||
return false;
|
||||
if (!checkIndex(index))
|
||||
return false;
|
||||
|
||||
int row = index.row();
|
||||
int col = index.column();
|
||||
int row = index.row();
|
||||
int col = index.column();
|
||||
|
||||
switch (col) {
|
||||
case ColumnType::Species:
|
||||
this->monInfo.wildPokemon[row].species = value.toString();
|
||||
break;
|
||||
|
||||
case ColumnType::MinLevel: {
|
||||
int minLevel = value.toInt();
|
||||
this->monInfo.wildPokemon[row].minLevel = minLevel;
|
||||
if (minLevel > this->monInfo.wildPokemon[row].maxLevel)
|
||||
this->monInfo.wildPokemon[row].maxLevel = minLevel;
|
||||
break;
|
||||
switch (col) {
|
||||
case ColumnType::Species: {
|
||||
QString species = value.toString();
|
||||
if (this->monInfo.wildPokemon[row].species != species) {
|
||||
this->monInfo.wildPokemon[row].species = species;
|
||||
emit edited();
|
||||
}
|
||||
|
||||
case ColumnType::MaxLevel: {
|
||||
int maxLevel = value.toInt();
|
||||
this->monInfo.wildPokemon[row].maxLevel = maxLevel;
|
||||
if (maxLevel < this->monInfo.wildPokemon[row].minLevel)
|
||||
this->monInfo.wildPokemon[row].minLevel = maxLevel;
|
||||
break;
|
||||
}
|
||||
|
||||
case ColumnType::EncounterRate:
|
||||
this->monInfo.encounterRate = value.toInt();
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
emit edited();
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
|
||||
case ColumnType::MinLevel: {
|
||||
int minLevel = value.toInt();
|
||||
if (this->monInfo.wildPokemon[row].minLevel != minLevel) {
|
||||
this->monInfo.wildPokemon[row].minLevel = minLevel;
|
||||
this->monInfo.wildPokemon[row].maxLevel = qMax(minLevel, this->monInfo.wildPokemon[row].maxLevel);
|
||||
emit edited();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ColumnType::MaxLevel: {
|
||||
int maxLevel = value.toInt();
|
||||
if (this->monInfo.wildPokemon[row].maxLevel != maxLevel) {
|
||||
this->monInfo.wildPokemon[row].maxLevel = maxLevel;
|
||||
this->monInfo.wildPokemon[row].minLevel = qMin(maxLevel, this->monInfo.wildPokemon[row].minLevel);
|
||||
emit edited();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ColumnType::EncounterRate: {
|
||||
int encounterRate = value.toInt();
|
||||
if (this->monInfo.encounterRate != encounterRate) {
|
||||
this->monInfo.encounterRate = encounterRate;
|
||||
emit edited();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::ItemFlags EncounterTableModel::flags(const QModelIndex &index) const {
|
||||
|
@ -199,7 +211,3 @@ Qt::ItemFlags EncounterTableModel::flags(const QModelIndex &index) const {
|
|||
}
|
||||
return flags | QAbstractTableModel::flags(index);
|
||||
}
|
||||
|
||||
WildMonInfo EncounterTableModel::encounterData() {
|
||||
return this->monInfo;
|
||||
}
|
||||
|
|
|
@ -360,7 +360,7 @@ void ObjectFrame::initialize() {
|
|||
|
||||
// script
|
||||
this->combo_script->setCurrentText(this->object->getScript());
|
||||
if (porymapConfig.getTextEditorGotoLine().isEmpty())
|
||||
if (porymapConfig.textEditorGotoLine.isEmpty())
|
||||
this->button_script->hide();
|
||||
|
||||
// flag
|
||||
|
@ -858,16 +858,16 @@ void HiddenItemFrame::initialize() {
|
|||
this->combo_flag->setTextItem(this->hiddenItem->getFlag());
|
||||
|
||||
// quantity
|
||||
if (projectConfig.getHiddenItemQuantityEnabled()) {
|
||||
if (projectConfig.hiddenItemQuantityEnabled) {
|
||||
this->spinner_quantity->setValue(this->hiddenItem->getQuantity());
|
||||
}
|
||||
this->hideable_quantity->setVisible(projectConfig.getHiddenItemQuantityEnabled());
|
||||
this->hideable_quantity->setVisible(projectConfig.hiddenItemQuantityEnabled);
|
||||
|
||||
// underfoot
|
||||
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
|
||||
if (projectConfig.hiddenItemRequiresItemfinderEnabled) {
|
||||
this->check_itemfinder->setChecked(this->hiddenItem->getUnderfoot());
|
||||
}
|
||||
this->hideable_itemfinder->setVisible(projectConfig.getHiddenItemRequiresItemfinderEnabled());
|
||||
this->hideable_itemfinder->setVisible(projectConfig.hiddenItemRequiresItemfinderEnabled);
|
||||
}
|
||||
|
||||
void HiddenItemFrame::populate(Project *project) {
|
||||
|
@ -971,7 +971,7 @@ void HealLocationFrame::connectSignals(MainWindow *window) {
|
|||
|
||||
EventFrame::connectSignals(window);
|
||||
|
||||
if (projectConfig.getHealLocationRespawnDataEnabled()) {
|
||||
if (projectConfig.healLocationRespawnDataEnabled) {
|
||||
this->combo_respawn_map->disconnect();
|
||||
connect(this->combo_respawn_map, &QComboBox::currentTextChanged, [this](const QString &text) {
|
||||
this->healLocation->setRespawnMap(text);
|
||||
|
@ -992,7 +992,7 @@ void HealLocationFrame::initialize() {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::initialize();
|
||||
|
||||
bool respawnEnabled = projectConfig.getHealLocationRespawnDataEnabled();
|
||||
bool respawnEnabled = projectConfig.healLocationRespawnDataEnabled;
|
||||
if (respawnEnabled) {
|
||||
this->combo_respawn_map->setTextItem(this->healLocation->getRespawnMap());
|
||||
this->spinner_respawn_npc->setValue(this->healLocation->getRespawnNPC());
|
||||
|
@ -1008,6 +1008,6 @@ void HealLocationFrame::populate(Project *project) {
|
|||
const QSignalBlocker blocker(this);
|
||||
EventFrame::populate(project);
|
||||
|
||||
if (projectConfig.getHealLocationRespawnDataEnabled())
|
||||
if (projectConfig.healLocationRespawnDataEnabled)
|
||||
this->combo_respawn_map->addItems(project->mapNames);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ QImage getMetatileImage(
|
|||
QList<QList<QRgb>> palettes = Tileset::getBlockPalettes(primaryTileset, secondaryTileset, useTruePalettes);
|
||||
|
||||
QPainter metatile_painter(&metatile_image);
|
||||
bool isTripleLayerMetatile = projectConfig.getTripleLayerMetatilesEnabled();
|
||||
const int numLayers = 3; // When rendering, metatiles always have 3 layers
|
||||
uint32_t layerType = metatile->layerType();
|
||||
for (int layer = 0; layer < numLayers; layer++)
|
||||
|
@ -60,7 +59,7 @@ QImage getMetatileImage(
|
|||
// Get the tile to render next
|
||||
Tile tile;
|
||||
int tileOffset = (y * 2) + x;
|
||||
if (isTripleLayerMetatile) {
|
||||
if (projectConfig.tripleLayerMetatilesEnabled) {
|
||||
tile = metatile->tiles.value(tileOffset + (l * 4));
|
||||
} else {
|
||||
// "Vanilla" metatiles only have 8 tiles, but render 12.
|
||||
|
|
|
@ -27,13 +27,14 @@ MapImageExporter::MapImageExporter(QWidget *parent_, Editor *editor_, ImageExpor
|
|||
QDialog(parent_),
|
||||
ui(new Ui::MapImageExporter)
|
||||
{
|
||||
this->setAttribute(Qt::WA_DeleteOnClose);
|
||||
ui->setupUi(this);
|
||||
this->map = editor_->map;
|
||||
this->layout = editor_->layout;
|
||||
this->editor = editor_;
|
||||
this->mode = mode;
|
||||
this->setWindowTitle(getTitle(this->mode));
|
||||
this->ui->groupBox_Connections->setVisible(this->mode == ImageExporterMode::Normal);
|
||||
this->ui->groupBox_Connections->setVisible(this->mode != ImageExporterMode::Stitch);
|
||||
this->ui->groupBox_Timelapse->setVisible(this->mode == ImageExporterMode::Timelapse);
|
||||
|
||||
if (this->map) {
|
||||
|
@ -175,7 +176,7 @@ void MapImageExporter::saveImage() {
|
|||
}
|
||||
}
|
||||
// The latest map state is the last animated frame.
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(this->map, !this->showBorder);
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(this->map);
|
||||
timelapseImg.addFrame(pixmap.toImage());
|
||||
progress.close();
|
||||
};
|
||||
|
@ -194,6 +195,9 @@ void MapImageExporter::saveImage() {
|
|||
}
|
||||
|
||||
bool MapImageExporter::historyItemAppliesToFrame(const QUndoCommand *command) {
|
||||
if (command->isObsolete())
|
||||
return false;
|
||||
|
||||
switch (command->id() & 0xFF) {
|
||||
case CommandId::ID_PaintMetatile:
|
||||
case CommandId::ID_BucketFillMetatile:
|
||||
|
@ -208,6 +212,12 @@ bool MapImageExporter::historyItemAppliesToFrame(const QUndoCommand *command) {
|
|||
return this->showCollision;
|
||||
case CommandId::ID_PaintBorder:
|
||||
return this->showBorder;
|
||||
case CommandId::ID_MapConnectionMove:
|
||||
case CommandId::ID_MapConnectionChangeDirection:
|
||||
case CommandId::ID_MapConnectionChangeMap:
|
||||
case CommandId::ID_MapConnectionAdd:
|
||||
case CommandId::ID_MapConnectionRemove:
|
||||
return this->showUpConnections || this->showDownConnections || this->showLeftConnections || this->showRightConnections;
|
||||
case CommandId::ID_EventMove:
|
||||
case CommandId::ID_EventShift:
|
||||
case CommandId::ID_EventCreate:
|
||||
|
@ -254,25 +264,29 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress, bool inclu
|
|||
visited.insert(cur.map->name);
|
||||
stitchedMaps.append(cur);
|
||||
|
||||
for (MapConnection *connection : cur.map->connections) {
|
||||
if (connection->direction == "dive" || connection->direction == "emerge")
|
||||
continue;
|
||||
for (MapConnection *connection : cur.map->getConnections()) {
|
||||
const QString direction = connection->direction();
|
||||
int x = cur.x;
|
||||
int y = cur.y;
|
||||
int offset = connection->offset;
|
||||
Map *connectionMap = this->editor->project->loadMap(connection->map_name);
|
||||
if (connection->direction == "up") {
|
||||
int offset = connection->offset();
|
||||
Map *connectionMap = connection->targetMap();
|
||||
if (!connectionMap)
|
||||
continue;
|
||||
if (direction == "up") {
|
||||
x += offset;
|
||||
y -= connectionMap->getHeight();
|
||||
} else if (connection->direction == "down") {
|
||||
} else if (direction == "down") {
|
||||
x += offset;
|
||||
y += cur.map->getHeight();
|
||||
} else if (connection->direction == "left") {
|
||||
} else if (direction == "left") {
|
||||
x -= connectionMap->getWidth();
|
||||
y += offset;
|
||||
} else if (connection->direction == "right") {
|
||||
} else if (direction == "right") {
|
||||
x += cur.map->getWidth();
|
||||
y += offset;
|
||||
} else {
|
||||
// Ignore Dive/Emerge connections and unrecognized directions
|
||||
continue;
|
||||
}
|
||||
unvisited.append(StitchedMap{x, y, connectionMap});
|
||||
}
|
||||
|
@ -326,7 +340,7 @@ QPixmap MapImageExporter::getStitchedImage(QProgressDialog *progress, bool inclu
|
|||
pixelX -= STITCH_MODE_BORDER_DISTANCE * 16;
|
||||
pixelY -= STITCH_MODE_BORDER_DISTANCE * 16;
|
||||
}
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(map.map, false);
|
||||
QPixmap pixmap = this->getFormattedMapPixmap(map.map);
|
||||
painter.drawPixmap(pixelX, pixelY, pixmap);
|
||||
}
|
||||
|
||||
|
@ -361,7 +375,7 @@ void MapImageExporter::updatePreview() {
|
|||
scene = nullptr;
|
||||
}
|
||||
|
||||
preview = getFormattedMapPixmap(this->map, false);
|
||||
preview = getFormattedMapPixmap(this->map);
|
||||
scene = new QGraphicsScene;
|
||||
scene->addPixmap(preview);
|
||||
this->scene->setSceneRect(this->scene->itemsBoundingRect());
|
||||
|
@ -399,8 +413,7 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
|||
// draw map border
|
||||
// note: this will break when allowing map to be selected from drop down maybe
|
||||
int borderHeight = 0, borderWidth = 0;
|
||||
bool forceDrawBorder = showUpConnections || showDownConnections || showLeftConnections || showRightConnections;
|
||||
if (!ignoreBorder && (showBorder || forceDrawBorder)) {
|
||||
if (!ignoreBorder && this->showBorder) {
|
||||
int borderDistance = this->mode ? STITCH_MODE_BORDER_DISTANCE : BORDER_DISTANCE;
|
||||
layout->renderBorder();
|
||||
int borderHorzDist = editor->getBorderDrawDistance(layout->getBorderWidth());
|
||||
|
@ -423,17 +436,17 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
|||
return pixmap;
|
||||
}
|
||||
|
||||
if (!this->mode) {
|
||||
if (!ignoreBorder && (this->showUpConnections || this->showDownConnections || this->showLeftConnections || this->showRightConnections)) {
|
||||
// if showing connections, draw on outside of image
|
||||
QPainter connectionPainter(&pixmap);
|
||||
for (auto connectionItem : editor->connection_items) {
|
||||
QString direction = connectionItem->connection->direction;
|
||||
const QString direction = connectionItem->connection->direction();
|
||||
if ((showUpConnections && direction == "up")
|
||||
|| (showDownConnections && direction == "down")
|
||||
|| (showLeftConnections && direction == "left")
|
||||
|| (showRightConnections && direction == "right"))
|
||||
connectionPainter.drawImage(connectionItem->initialX + borderWidth, connectionItem->initialY + borderHeight,
|
||||
connectionItem->basePixmap.toImage());
|
||||
connectionPainter.drawImage(connectionItem->x() + borderWidth, connectionItem->y() + borderHeight,
|
||||
connectionItem->connection->getPixmap().toImage());
|
||||
}
|
||||
connectionPainter.end();
|
||||
}
|
||||
|
@ -442,7 +455,7 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
|||
QPainter eventPainter(&pixmap);
|
||||
QList<Event *> events = map->getAllEvents();
|
||||
int pixelOffset = 0;
|
||||
if (!ignoreBorder && showBorder) {
|
||||
if (!ignoreBorder && this->showBorder) {
|
||||
pixelOffset = this->mode == ImageExporterMode::Normal ? BORDER_DISTANCE * 16 : STITCH_MODE_BORDER_DISTANCE * 16;
|
||||
}
|
||||
for (Event *event : events) {
|
||||
|
@ -480,6 +493,18 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
|||
return pixmap;
|
||||
}
|
||||
|
||||
void MapImageExporter::updateShowBorderState() {
|
||||
// If any of the Connections settings are enabled then this setting is locked (it's implicitly enabled)
|
||||
const QSignalBlocker blocker(ui->checkBox_Border);
|
||||
if (showUpConnections || showDownConnections || showLeftConnections || showRightConnections) {
|
||||
ui->checkBox_Border->setChecked(true);
|
||||
ui->checkBox_Border->setDisabled(true);
|
||||
showBorder = true;
|
||||
} else {
|
||||
ui->checkBox_Border->setDisabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MapImageExporter::on_checkBox_Elevation_stateChanged(int state) {
|
||||
showCollision = (state == Qt::Checked);
|
||||
updatePreview();
|
||||
|
@ -522,21 +547,25 @@ void MapImageExporter::on_checkBox_HealSpots_stateChanged(int state) {
|
|||
|
||||
void MapImageExporter::on_checkBox_ConnectionUp_stateChanged(int state) {
|
||||
showUpConnections = (state == Qt::Checked);
|
||||
updateShowBorderState();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void MapImageExporter::on_checkBox_ConnectionDown_stateChanged(int state) {
|
||||
showDownConnections = (state == Qt::Checked);
|
||||
updateShowBorderState();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void MapImageExporter::on_checkBox_ConnectionLeft_stateChanged(int state) {
|
||||
showLeftConnections = (state == Qt::Checked);
|
||||
updateShowBorderState();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void MapImageExporter::on_checkBox_ConnectionRight_stateChanged(int state) {
|
||||
showRightConnections = (state == Qt::Checked);
|
||||
updateShowBorderState();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ QMimeData *MapGroupModel::mimeData(const QModelIndexList &indexes) const {
|
|||
|
||||
// if dropping a selection containing a group(s) and map(s), clear all selection but first group.
|
||||
for (const QModelIndex &index : indexes) {
|
||||
if (index.isValid() && data(index, MapListRoles::TypeRole).toString() == "map_group") {
|
||||
if (index.isValid() && data(index, MapListUserRoles::TypeRole).toString() == "map_group") {
|
||||
QString groupName = data(index, Qt::UserRole).toString();
|
||||
stream << groupName;
|
||||
mimeData->setData("application/porymap.mapgroupmodel.group", encodedData);
|
||||
|
@ -221,8 +221,8 @@ QStandardItem *MapGroupModel::createGroupItem(QString groupName, int groupIndex,
|
|||
if (!group) group = new QStandardItem;
|
||||
group->setText(groupName);
|
||||
group->setData(groupName, Qt::UserRole);
|
||||
group->setData("map_group", MapListRoles::TypeRole);
|
||||
group->setData(groupIndex, MapListRoles::GroupRole);
|
||||
group->setData("map_group", MapListUserRoles::TypeRole);
|
||||
group->setData(groupIndex, MapListUserRoles::GroupRole);
|
||||
group->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable);
|
||||
this->groupItems.insert(groupName, group);
|
||||
return group;
|
||||
|
@ -231,7 +231,7 @@ QStandardItem *MapGroupModel::createGroupItem(QString groupName, int groupIndex,
|
|||
QStandardItem *MapGroupModel::createMapItem(QString mapName, QStandardItem *map) {
|
||||
if (!map) map = new QStandardItem;
|
||||
map->setData(mapName, Qt::UserRole);
|
||||
map->setData("map_name", MapListRoles::TypeRole);
|
||||
map->setData("map_name", MapListUserRoles::TypeRole);
|
||||
map->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
|
||||
this->mapItems[mapName] = map;
|
||||
return map;
|
||||
|
@ -315,7 +315,7 @@ QVariant MapGroupModel::data(const QModelIndex &index, int role) const {
|
|||
}
|
||||
|
||||
QStandardItem *item = this->getItem(index)->child(row, col);
|
||||
QString type = item->data(MapListRoles::TypeRole).toString();
|
||||
QString type = item->data(MapListUserRoles::TypeRole).toString();
|
||||
|
||||
if (type == "map_group") {
|
||||
if (!item->hasChildren()) {
|
||||
|
@ -340,7 +340,7 @@ QVariant MapGroupModel::data(const QModelIndex &index, int role) const {
|
|||
}
|
||||
else if (role == Qt::DisplayRole) {
|
||||
QStandardItem *item = this->getItem(index)->child(row, col);
|
||||
QString type = item->data(MapListRoles::TypeRole).toString();
|
||||
QString type = item->data(MapListUserRoles::TypeRole).toString();
|
||||
|
||||
if (type == "map_name") {
|
||||
return QString("[%1.%2] ").arg(this->getItem(index)->row()).arg(row, 2, 10, QLatin1Char('0')) + item->data(Qt::UserRole).toString();
|
||||
|
@ -354,7 +354,7 @@ QVariant MapGroupModel::data(const QModelIndex &index, int role) const {
|
|||
}
|
||||
|
||||
bool MapGroupModel::setData(const QModelIndex &index, const QVariant &value, int role) {
|
||||
if (role == Qt::UserRole && data(index, MapListRoles::TypeRole).toString() == "map_group") {
|
||||
if (role == Qt::UserRole && data(index, MapListUserRoles::TypeRole).toString() == "map_group") {
|
||||
// verify uniqueness of new group name
|
||||
if (this->project->groupNames.contains(value.toString())) {
|
||||
return false;
|
||||
|
@ -379,8 +379,8 @@ QStandardItem *MapAreaModel::createAreaItem(QString mapsecName, int areaIndex) {
|
|||
area->setText(mapsecName);
|
||||
area->setEditable(false);
|
||||
area->setData(mapsecName, Qt::UserRole);
|
||||
area->setData("map_section", MapListRoles::TypeRole);
|
||||
area->setData(areaIndex, MapListRoles::GroupRole);
|
||||
area->setData("map_section", MapListUserRoles::TypeRole);
|
||||
area->setData(areaIndex, MapListUserRoles::GroupRole);
|
||||
// group->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
|
||||
this->areaItems.insert(mapsecName, area);
|
||||
return area;
|
||||
|
@ -391,7 +391,7 @@ QStandardItem *MapAreaModel::createMapItem(QString mapName, int groupIndex, int
|
|||
map->setText(mapName);
|
||||
map->setEditable(false);
|
||||
map->setData(mapName, Qt::UserRole);
|
||||
map->setData("map_name", MapListRoles::TypeRole);
|
||||
map->setData("map_name", MapListUserRoles::TypeRole);
|
||||
// map->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
|
||||
this->mapItems.insert(mapName, map);
|
||||
return map;
|
||||
|
@ -401,7 +401,7 @@ QStandardItem *MapAreaModel::insertAreaItem(QString areaName) {
|
|||
int newAreaIndex = this->project->appendMapsec(areaName);
|
||||
QStandardItem *item = createAreaItem(areaName, newAreaIndex);
|
||||
this->root->insertRow(newAreaIndex, item);
|
||||
this->areaItems["MAPSEC_NONE"]->setData(newAreaIndex + 1, MapListRoles::GroupRole);
|
||||
this->areaItems["MAPSEC_NONE"]->setData(newAreaIndex + 1, MapListUserRoles::GroupRole);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
@ -425,7 +425,7 @@ void MapAreaModel::removeArea(int areaIndex) {
|
|||
void MapAreaModel::initialize() {
|
||||
this->areaItems.clear();
|
||||
this->mapItems.clear();
|
||||
this->setSortRole(MapListRoles::GroupRole);
|
||||
this->setSortRole(MapListUserRoles::GroupRole);
|
||||
|
||||
for (int i : this->project->mapSectionNameToValue) {
|
||||
QString mapsecName = project->mapSectionValueToName.value(i);
|
||||
|
@ -487,7 +487,7 @@ QVariant MapAreaModel::data(const QModelIndex &index, int role) const {
|
|||
}
|
||||
|
||||
QStandardItem *item = this->getItem(index)->child(row, col);
|
||||
QString type = item->data(MapListRoles::TypeRole).toString();
|
||||
QString type = item->data(MapListUserRoles::TypeRole).toString();
|
||||
|
||||
if (type == "map_section") {
|
||||
if (item->hasChildren()) {
|
||||
|
@ -512,11 +512,11 @@ QVariant MapAreaModel::data(const QModelIndex &index, int role) const {
|
|||
}
|
||||
else if (role == Qt::DisplayRole) {
|
||||
QStandardItem *item = this->getItem(index)->child(row, col);
|
||||
QString type = item->data(MapListRoles::TypeRole).toString();
|
||||
QString type = item->data(MapListUserRoles::TypeRole).toString();
|
||||
|
||||
if (type == "map_section") {
|
||||
return QString("[0x%1] %2")
|
||||
.arg(QString("%1").arg(item->data(MapListRoles::GroupRole).toInt(), 2, 16, QLatin1Char('0')).toUpper())
|
||||
.arg(QString("%1").arg(item->data(MapListUserRoles::GroupRole).toInt(), 2, 16, QLatin1Char('0')).toUpper())
|
||||
.arg(item->data(Qt::UserRole).toString());
|
||||
}
|
||||
}
|
||||
|
@ -538,7 +538,7 @@ QStandardItem *LayoutTreeModel::createLayoutItem(QString layoutId) {
|
|||
layout->setText(this->project->layoutIdsToNames[layoutId]);
|
||||
layout->setEditable(false);
|
||||
layout->setData(layoutId, Qt::UserRole);
|
||||
layout->setData("map_layout", MapListRoles::TypeRole);
|
||||
layout->setData("map_layout", MapListUserRoles::TypeRole);
|
||||
// // group->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
|
||||
this->layoutItems.insert(layoutId, layout);
|
||||
return layout;
|
||||
|
@ -549,7 +549,7 @@ QStandardItem *LayoutTreeModel::createMapItem(QString mapName) {
|
|||
map->setText(mapName);
|
||||
map->setEditable(false);
|
||||
map->setData(mapName, Qt::UserRole);
|
||||
map->setData("map_name", MapListRoles::TypeRole);
|
||||
map->setData("map_name", MapListUserRoles::TypeRole);
|
||||
map->setFlags(Qt::NoItemFlags | Qt::ItemNeverHasChildren);
|
||||
this->mapItems.insert(mapName, map);
|
||||
return map;
|
||||
|
@ -624,7 +624,7 @@ QVariant LayoutTreeModel::data(const QModelIndex &index, int role) const {
|
|||
static QIcon mapOpenedIcon = QIcon(QStringLiteral(":/icons/map_opened.ico"));
|
||||
|
||||
QStandardItem *item = this->getItem(index)->child(row, col);
|
||||
QString type = item->data(MapListRoles::TypeRole).toString();
|
||||
QString type = item->data(MapListUserRoles::TypeRole).toString();
|
||||
|
||||
if (type == "map_layout") {
|
||||
QString layoutId = item->data(Qt::UserRole).toString();
|
||||
|
|
|
@ -62,7 +62,7 @@ void MonTabWidget::paste(int index) {
|
|||
WildMonInfo newInfo = getDefaultMonInfo(this->editor->project->wildMonFields.at(index));
|
||||
combineEncounters(newInfo, encounterClipboard);
|
||||
populateTab(index, newInfo);
|
||||
emit editor->wildMonDataChanged();
|
||||
emit editor->wildMonTableEdited();
|
||||
}
|
||||
|
||||
void MonTabWidget::actionCopyTab(int index) {
|
||||
|
@ -82,21 +82,19 @@ void MonTabWidget::actionCopyTab(int index) {
|
|||
}
|
||||
|
||||
void MonTabWidget::actionAddDeleteTab(int index) {
|
||||
clearTableAt(index);
|
||||
if (activeTabs[index]) {
|
||||
// delete tab
|
||||
clearTableAt(index);
|
||||
deactivateTab(index);
|
||||
editor->saveEncounterTabData();
|
||||
emit editor->wildMonDataChanged();
|
||||
}
|
||||
else {
|
||||
// add tab
|
||||
clearTableAt(index);
|
||||
populateTab(index, getDefaultMonInfo(editor->project->wildMonFields.at(index)));
|
||||
editor->saveEncounterTabData();
|
||||
setCurrentIndex(index);
|
||||
emit editor->wildMonDataChanged();
|
||||
}
|
||||
emit editor->wildMonTableEdited();
|
||||
}
|
||||
|
||||
void MonTabWidget::clearTableAt(int tabIndex) {
|
||||
|
@ -124,6 +122,7 @@ void MonTabWidget::populateTab(int tabIndex, WildMonInfo monInfo) {
|
|||
|
||||
EncounterTableModel *model = new EncounterTableModel(monInfo, editor->project->wildMonFields, tabIndex, this);
|
||||
connect(model, &EncounterTableModel::edited, editor, &Editor::saveEncounterTabData);
|
||||
connect(model, &EncounterTableModel::edited, editor, &Editor::wildMonTableEdited);
|
||||
speciesTable->setModel(model);
|
||||
|
||||
speciesTable->setItemDelegateForColumn(EncounterTableModel::ColumnType::Species, new SpeciesComboDelegate(editor->project, this));
|
||||
|
@ -152,6 +151,8 @@ void MonTabWidget::populateTab(int tabIndex, WildMonInfo monInfo) {
|
|||
}
|
||||
|
||||
QTableView *MonTabWidget::tableAt(int tabIndex) {
|
||||
if (tabIndex < 0)
|
||||
return nullptr;
|
||||
return static_cast<QTableView *>(this->widget(tabIndex));
|
||||
}
|
||||
|
||||
|
|
72
src/ui/newmapconnectiondialog.cpp
Normal file
72
src/ui/newmapconnectiondialog.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "newmapconnectiondialog.h"
|
||||
#include "ui_newmapconnectiondialog.h"
|
||||
|
||||
NewMapConnectionDialog::NewMapConnectionDialog(QWidget *parent, Map* map, const QStringList &mapNames) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::NewMapConnectionDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
ui->comboBox_Direction->setEditable(false);
|
||||
ui->comboBox_Direction->addItems(MapConnection::cardinalDirections);
|
||||
|
||||
ui->comboBox_Map->addItems(mapNames);
|
||||
ui->comboBox_Map->setInsertPolicy(QComboBox::NoInsert);
|
||||
|
||||
// Choose default direction
|
||||
QMap<QString, int> directionCounts;
|
||||
for (auto connection : map->getConnections()) {
|
||||
directionCounts[connection->direction()]++;
|
||||
}
|
||||
QString defaultDirection;
|
||||
int minCount = INT_MAX;
|
||||
for (auto direction : MapConnection::cardinalDirections) {
|
||||
if (directionCounts[direction] < minCount) {
|
||||
defaultDirection = direction;
|
||||
minCount = directionCounts[direction];
|
||||
}
|
||||
}
|
||||
ui->comboBox_Direction->setTextItem(defaultDirection);
|
||||
|
||||
// Choose default map
|
||||
QString defaultMapName;
|
||||
if (mapNames.isEmpty()) {
|
||||
defaultMapName = QString();
|
||||
} else if (mapNames.first() == map->name && mapNames.length() > 1) {
|
||||
// Prefer not to connect the map to itself
|
||||
defaultMapName = mapNames.at(1);
|
||||
} else {
|
||||
defaultMapName = mapNames.first();
|
||||
}
|
||||
ui->comboBox_Map->setTextItem(defaultMapName);
|
||||
|
||||
connect(ui->comboBox_Map, &QComboBox::currentTextChanged, [this] {
|
||||
if (ui->label_Warning->isVisible() && mapNameIsValid())
|
||||
setWarningVisible(false);
|
||||
});
|
||||
setWarningVisible(false);
|
||||
}
|
||||
|
||||
NewMapConnectionDialog::~NewMapConnectionDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool NewMapConnectionDialog::mapNameIsValid() {
|
||||
return ui->comboBox_Map->findText(ui->comboBox_Map->currentText()) >= 0;
|
||||
}
|
||||
|
||||
void NewMapConnectionDialog::setWarningVisible(bool visible) {
|
||||
ui->label_Warning->setVisible(visible);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void NewMapConnectionDialog::accept() {
|
||||
if (!mapNameIsValid()) {
|
||||
setWarningVisible(true);
|
||||
return;
|
||||
}
|
||||
emit accepted(new MapConnection(ui->comboBox_Map->currentText(), ui->comboBox_Direction->currentText()));
|
||||
QDialog::accept();
|
||||
}
|
|
@ -14,6 +14,7 @@ NewMapPopup::NewMapPopup(QWidget *parent, Project *project) :
|
|||
QMainWindow(parent),
|
||||
ui(new Ui::NewMapPopup)
|
||||
{
|
||||
this->setAttribute(Qt::WA_DeleteOnClose);
|
||||
ui->setupUi(this);
|
||||
this->project = project;
|
||||
this->existingLayout = false;
|
||||
|
@ -52,7 +53,7 @@ void NewMapPopup::initUi() {
|
|||
ui->spinBox_NewMap_Floor_Number->setMaximum(127);
|
||||
|
||||
// Hide config specific ui elements
|
||||
bool hasFlags = projectConfig.getMapAllowFlagsEnabled();
|
||||
bool hasFlags = projectConfig.mapAllowFlagsEnabled;
|
||||
ui->checkBox_NewMap_Allow_Running->setVisible(hasFlags);
|
||||
ui->checkBox_NewMap_Allow_Biking->setVisible(hasFlags);
|
||||
ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(hasFlags);
|
||||
|
@ -60,13 +61,13 @@ void NewMapPopup::initUi() {
|
|||
ui->label_NewMap_Allow_Biking->setVisible(hasFlags);
|
||||
ui->label_NewMap_Allow_Escape_Rope->setVisible(hasFlags);
|
||||
|
||||
bool hasCustomBorders = projectConfig.getUseCustomBorderSize();
|
||||
bool hasCustomBorders = projectConfig.useCustomBorderSize;
|
||||
ui->spinBox_NewMap_BorderWidth->setVisible(hasCustomBorders);
|
||||
ui->spinBox_NewMap_BorderHeight->setVisible(hasCustomBorders);
|
||||
ui->label_NewMap_BorderWidth->setVisible(hasCustomBorders);
|
||||
ui->label_NewMap_BorderHeight->setVisible(hasCustomBorders);
|
||||
|
||||
bool hasFloorNumber = projectConfig.getFloorNumberEnabled();
|
||||
bool hasFloorNumber = projectConfig.floorNumberEnabled;
|
||||
ui->spinBox_NewMap_Floor_Number->setVisible(hasFloorNumber);
|
||||
ui->label_NewMap_Floor_Number->setVisible(hasFloorNumber);
|
||||
|
||||
|
@ -314,7 +315,7 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
|
|||
layout->name = QString("%1_Layout").arg(newMap->name);
|
||||
layout->width = this->ui->spinBox_NewMap_Width->value();
|
||||
layout->height = this->ui->spinBox_NewMap_Height->value();
|
||||
if (projectConfig.getUseCustomBorderSize()) {
|
||||
if (projectConfig.useCustomBorderSize) {
|
||||
layout->border_width = this->ui->spinBox_NewMap_BorderWidth->value();
|
||||
layout->border_height = this->ui->spinBox_NewMap_BorderHeight->value();
|
||||
} else {
|
||||
|
@ -338,12 +339,12 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
|
|||
newMap->needsHealLocation = true;
|
||||
}
|
||||
|
||||
if (projectConfig.getMapAllowFlagsEnabled()) {
|
||||
if (projectConfig.mapAllowFlagsEnabled) {
|
||||
newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked();
|
||||
newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked();
|
||||
newMap->allowEscaping = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked();
|
||||
}
|
||||
if (projectConfig.getFloorNumberEnabled()) {
|
||||
if (projectConfig.floorNumberEnabled) {
|
||||
newMap->floorNumber = this->ui->spinBox_NewMap_Floor_Number->value();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ NewTilesetDialog::NewTilesetDialog(Project* project, QWidget *parent) :
|
|||
QRegularExpressionValidator *validator = new QRegularExpressionValidator(expression);
|
||||
this->ui->nameLineEdit->setValidator(validator);
|
||||
|
||||
bool checkerboard = porymapConfig.getTilesetCheckerboardFill();
|
||||
bool checkerboard = porymapConfig.tilesetCheckerboardFill;
|
||||
this->ui->fillCheckBox->setChecked(checkerboard);
|
||||
this->checkerboardFill = checkerboard;
|
||||
|
||||
|
@ -46,5 +46,5 @@ void NewTilesetDialog::NameOrSecondaryChanged() {
|
|||
|
||||
void NewTilesetDialog::FillChanged() {
|
||||
this->checkerboardFill = this->ui->fillCheckBox->isChecked();
|
||||
porymapConfig.setTilesetCheckerboardFill(this->checkerboardFill);
|
||||
porymapConfig.tilesetCheckerboardFill = this->checkerboardFill;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "noscrollcombobox.h"
|
||||
|
||||
#include <QCompleter>
|
||||
#include <QLineEdit>
|
||||
|
||||
NoScrollComboBox::NoScrollComboBox(QWidget *parent)
|
||||
: QComboBox(parent)
|
||||
|
@ -22,13 +23,31 @@ NoScrollComboBox::NoScrollComboBox(QWidget *parent)
|
|||
this->setValidator(validator);
|
||||
}
|
||||
|
||||
// On macOS QComboBox::setEditable and QComboBox::setLineEdit will override our changes to the focus policy, so we enforce it here.
|
||||
void NoScrollComboBox::setEditable(bool editable) {
|
||||
auto policy = focusPolicy();
|
||||
QComboBox::setEditable(editable);
|
||||
setFocusPolicy(policy);
|
||||
}
|
||||
void NoScrollComboBox::setLineEdit(QLineEdit *edit) {
|
||||
auto policy = focusPolicy();
|
||||
QComboBox::setLineEdit(edit);
|
||||
setFocusPolicy(policy);
|
||||
}
|
||||
|
||||
void NoScrollComboBox::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
// Only allow scrolling to modify contents when it explicitly has focus.
|
||||
if (hasFocus())
|
||||
// By default NoScrollComboBoxes will allow scrolling to modify its contents only when it explicitly has focus.
|
||||
// If focusedScrollingEnabled is false it won't allow scrolling even with focus.
|
||||
if (this->focusedScrollingEnabled && hasFocus())
|
||||
QComboBox::wheelEvent(event);
|
||||
}
|
||||
|
||||
void NoScrollComboBox::setFocusedScrollingEnabled(bool enabled)
|
||||
{
|
||||
this->focusedScrollingEnabled = enabled;
|
||||
}
|
||||
|
||||
void NoScrollComboBox::setItem(int index, const QString &text)
|
||||
{
|
||||
if (index >= 0) {
|
||||
|
@ -61,3 +80,8 @@ void NoScrollComboBox::setHexItem(uint32_t value)
|
|||
{
|
||||
this->setItem(this->findData(value), "0x" + QString::number(value, 16).toUpper());
|
||||
}
|
||||
|
||||
void NoScrollComboBox::setClearButtonEnabled(bool enabled) {
|
||||
if (this->lineEdit())
|
||||
this->lineEdit()->setClearButtonEnabled(enabled);
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ PaletteEditor::PaletteEditor(Project *project, Tileset *primaryTileset, Tileset
|
|||
connect(this->pickButtons[i], &QToolButton::clicked, [this, i](){ this->pickColor(i); });
|
||||
}
|
||||
|
||||
int bitDepth = porymapConfig.getPaletteEditorBitDepth();
|
||||
int bitDepth = porymapConfig.paletteEditorBitDepth;
|
||||
if (bitDepth == 15) {
|
||||
this->ui->bit_depth_15->setChecked(true);
|
||||
} else {
|
||||
|
@ -233,7 +233,7 @@ void PaletteEditor::setBitDepth(int bits) {
|
|||
break;
|
||||
}
|
||||
this->bitDepth = bits;
|
||||
porymapConfig.setPaletteEditorBitDepth(bits);
|
||||
porymapConfig.paletteEditorBitDepth = bits;
|
||||
refreshColorUis();
|
||||
setSignalsEnabled(true);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ const QString defaultFilepath = "prefabs.json";
|
|||
|
||||
void Prefab::loadPrefabs() {
|
||||
this->items.clear();
|
||||
QString filepath = projectConfig.getPrefabFilepath();
|
||||
QString filepath = projectConfig.prefabFilepath;
|
||||
if (filepath.isEmpty()) return;
|
||||
|
||||
ParseUtil parser;
|
||||
|
@ -86,15 +86,14 @@ void Prefab::loadPrefabs() {
|
|||
}
|
||||
|
||||
void Prefab::savePrefabs() {
|
||||
QString filepath = projectConfig.getPrefabFilepath();
|
||||
if (filepath.isEmpty()) {
|
||||
filepath = defaultFilepath;
|
||||
projectConfig.setPrefabFilepath(filepath);
|
||||
}
|
||||
if (projectConfig.prefabFilepath.isEmpty())
|
||||
projectConfig.prefabFilepath = defaultFilepath;
|
||||
|
||||
QString filepath = projectConfig.prefabFilepath;
|
||||
|
||||
QFileInfo info(filepath);
|
||||
if (info.isRelative()) {
|
||||
filepath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + filepath);
|
||||
filepath = QDir::cleanPath(projectConfig.projectDir + QDir::separator() + filepath);
|
||||
}
|
||||
QFile prefabsFile(filepath);
|
||||
if (!prefabsFile.open(QIODevice::WriteOnly)) {
|
||||
|
@ -287,7 +286,7 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version,
|
|||
if (fileInfo.suffix().isEmpty())
|
||||
filepath += ".json";
|
||||
if (fileInfo.isRelative()) {
|
||||
absFilepath = QDir::cleanPath(projectConfig.getProjectDir() + QDir::separator() + filepath);
|
||||
absFilepath = QDir::cleanPath(projectConfig.projectDir + QDir::separator() + filepath);
|
||||
} else {
|
||||
absFilepath = filepath;
|
||||
}
|
||||
|
@ -313,10 +312,10 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version,
|
|||
bool acceptedImport = (prompt == QMessageBox::Yes);
|
||||
if (acceptedImport) {
|
||||
// Sets up the default prefabs.json filepath.
|
||||
projectConfig.setPrefabFilepath(filepath);
|
||||
projectConfig.prefabFilepath = filepath;
|
||||
QFile prefabsFile(absFilepath);
|
||||
if (!prefabsFile.open(QIODevice::WriteOnly)) {
|
||||
projectConfig.setPrefabFilepath(QString());
|
||||
projectConfig.prefabFilepath = QString();
|
||||
|
||||
logError(QString("Error: Could not open %1 for writing").arg(absFilepath));
|
||||
QMessageBox messageBox(parent);
|
||||
|
@ -339,6 +338,9 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version,
|
|||
case BaseGameVersion::pokeemerald:
|
||||
content = parser.readTextFile(":/text/prefabs_default_emerald.json");
|
||||
break;
|
||||
default:
|
||||
content = QString();
|
||||
break;
|
||||
}
|
||||
|
||||
prefabsFile.write(content.toUtf8());
|
||||
|
@ -346,7 +348,7 @@ bool Prefab::tryImportDefaultPrefabs(QWidget * parent, BaseGameVersion version,
|
|||
this->loadPrefabs();
|
||||
}
|
||||
|
||||
projectConfig.setPrefabImportPrompted(true);
|
||||
projectConfig.prefabImportPrompted = true;
|
||||
return acceptedImport;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,28 +44,26 @@ void PreferenceEditor::initFields() {
|
|||
}
|
||||
|
||||
void PreferenceEditor::updateFields() {
|
||||
themeSelector->setCurrentText(porymapConfig.getTheme());
|
||||
ui->lineEdit_TextEditorOpenFolder->setText(porymapConfig.getTextEditorOpenFolder());
|
||||
ui->lineEdit_TextEditorGotoLine->setText(porymapConfig.getTextEditorGotoLine());
|
||||
ui->checkBox_MonitorProjectFiles->setChecked(porymapConfig.getMonitorFiles());
|
||||
ui->checkBox_OpenRecentProject->setChecked(porymapConfig.getReopenOnLaunch());
|
||||
ui->checkBox_CheckForUpdates->setChecked(porymapConfig.getCheckForUpdates());
|
||||
themeSelector->setCurrentText(porymapConfig.theme);
|
||||
ui->lineEdit_TextEditorOpenFolder->setText(porymapConfig.textEditorOpenFolder);
|
||||
ui->lineEdit_TextEditorGotoLine->setText(porymapConfig.textEditorGotoLine);
|
||||
ui->checkBox_MonitorProjectFiles->setChecked(porymapConfig.monitorFiles);
|
||||
ui->checkBox_OpenRecentProject->setChecked(porymapConfig.reopenOnLaunch);
|
||||
ui->checkBox_CheckForUpdates->setChecked(porymapConfig.checkForUpdates);
|
||||
}
|
||||
|
||||
void PreferenceEditor::saveFields() {
|
||||
if (themeSelector->currentText() != porymapConfig.getTheme()) {
|
||||
if (themeSelector->currentText() != porymapConfig.theme) {
|
||||
const auto theme = themeSelector->currentText();
|
||||
porymapConfig.setTheme(theme);
|
||||
porymapConfig.theme = theme;
|
||||
emit themeChanged(theme);
|
||||
}
|
||||
|
||||
porymapConfig.setSaveDisabled(true);
|
||||
porymapConfig.setTextEditorOpenFolder(ui->lineEdit_TextEditorOpenFolder->text());
|
||||
porymapConfig.setTextEditorGotoLine(ui->lineEdit_TextEditorGotoLine->text());
|
||||
porymapConfig.setMonitorFiles(ui->checkBox_MonitorProjectFiles->isChecked());
|
||||
porymapConfig.setReopenOnLaunch(ui->checkBox_OpenRecentProject->isChecked());
|
||||
porymapConfig.setCheckForUpdates(ui->checkBox_CheckForUpdates->isChecked());
|
||||
porymapConfig.setSaveDisabled(false);
|
||||
porymapConfig.textEditorOpenFolder = ui->lineEdit_TextEditorOpenFolder->text();
|
||||
porymapConfig.textEditorGotoLine = ui->lineEdit_TextEditorGotoLine->text();
|
||||
porymapConfig.monitorFiles = ui->checkBox_MonitorProjectFiles->isChecked();
|
||||
porymapConfig.reopenOnLaunch = ui->checkBox_OpenRecentProject->isChecked();
|
||||
porymapConfig.checkForUpdates = ui->checkBox_CheckForUpdates->isChecked();
|
||||
porymapConfig.save();
|
||||
|
||||
emit preferencesSaved();
|
||||
|
|
|
@ -18,7 +18,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(QWidget *parent, Project *project)
|
|||
QMainWindow(parent),
|
||||
ui(new Ui::ProjectSettingsEditor),
|
||||
project(project),
|
||||
baseDir(userConfig.getProjectDir() + QDir::separator())
|
||||
baseDir(projectConfig.projectDir + QDir::separator())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
@ -109,7 +109,7 @@ void ProjectSettingsEditor::initUi() {
|
|||
static const QRegularExpression expression_HexList(QString("^(%1,)*%1$").arg(regex_Hex)); // Comma-separated list of hex values
|
||||
QRegularExpressionValidator *validator_HexList = new QRegularExpressionValidator(expression_HexList);
|
||||
ui->lineEdit_BorderMetatiles->setValidator(validator_HexList);
|
||||
this->setBorderMetatilesUi(projectConfig.getUseCustomBorderSize());
|
||||
this->setBorderMetatilesUi(projectConfig.useCustomBorderSize);
|
||||
|
||||
// Validate that the text added to the warp behavior list could be a valid define
|
||||
// (we don't care whether it actually is a metatile behavior define)
|
||||
|
@ -133,63 +133,50 @@ void ProjectSettingsEditor::initUi() {
|
|||
ui->spinBox_CollisionMask->setMaximum(Block::maxValue);
|
||||
ui->spinBox_ElevationMask->setMaximum(Block::maxValue);
|
||||
|
||||
// Some settings can be determined by constants in the project.
|
||||
// We reflect that here by disabling their UI elements.
|
||||
if (project) {
|
||||
const QString maskFilepath = projectConfig.getFilePath(ProjectFilePath::global_fieldmap);
|
||||
const QString attrTableFilepath = projectConfig.getFilePath(ProjectFilePath::fieldmap);
|
||||
const QString metatileIdMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_metatile);
|
||||
const QString collisionMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_collision);
|
||||
const QString elevationMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_elevation);
|
||||
const QString behaviorMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_behavior);
|
||||
const QString layerTypeMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_layer);
|
||||
const QString behaviorTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_behavior);
|
||||
const QString layerTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_layer);
|
||||
const QString encounterTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_encounter);
|
||||
const QString terrainTypeTableName = projectConfig.getIdentifier(ProjectIdentifier::define_attribute_terrain);
|
||||
const QString attrTableName = projectConfig.getIdentifier(ProjectIdentifier::symbol_attribute_table);
|
||||
// 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.
|
||||
const QString globalFieldmapPath = projectConfig.getFilePath(ProjectFilePath::global_fieldmap);
|
||||
const QString constantsFieldmapPath = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap);
|
||||
const QString fieldmapPath = projectConfig.getFilePath(ProjectFilePath::fieldmap);
|
||||
|
||||
// Block masks
|
||||
if (project->disabledSettingsNames.contains(metatileIdMaskName))
|
||||
this->disableParsedSetting(ui->spinBox_MetatileIdMask, metatileIdMaskName, maskFilepath);
|
||||
if (project->disabledSettingsNames.contains(collisionMaskName))
|
||||
this->disableParsedSetting(ui->spinBox_CollisionMask, collisionMaskName, maskFilepath);
|
||||
if (project->disabledSettingsNames.contains(elevationMaskName))
|
||||
this->disableParsedSetting(ui->spinBox_ElevationMask, elevationMaskName, maskFilepath);
|
||||
// Block masks
|
||||
this->disableParsedSetting(ui->spinBox_MetatileIdMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_metatile), globalFieldmapPath);
|
||||
this->disableParsedSetting(ui->spinBox_CollisionMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_collision), globalFieldmapPath);
|
||||
this->disableParsedSetting(ui->spinBox_ElevationMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_elevation), globalFieldmapPath);
|
||||
|
||||
// Behavior mask
|
||||
if (project->disabledSettingsNames.contains(behaviorMaskName))
|
||||
this->disableParsedSetting(ui->spinBox_BehaviorMask, behaviorMaskName, maskFilepath);
|
||||
else if (project->disabledSettingsNames.contains(behaviorTableName))
|
||||
this->disableParsedSetting(ui->spinBox_BehaviorMask, attrTableName, attrTableFilepath);
|
||||
// Behavior mask
|
||||
if (!this->disableParsedSetting(ui->spinBox_BehaviorMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_behavior), globalFieldmapPath))
|
||||
this->disableParsedSetting(ui->spinBox_BehaviorMask, projectConfig.getIdentifier(ProjectIdentifier::define_attribute_behavior), fieldmapPath);
|
||||
|
||||
// Layer type mask
|
||||
if (project->disabledSettingsNames.contains(layerTypeMaskName))
|
||||
this->disableParsedSetting(ui->spinBox_LayerTypeMask, layerTypeMaskName, maskFilepath);
|
||||
else if (project->disabledSettingsNames.contains(layerTypeTableName))
|
||||
this->disableParsedSetting(ui->spinBox_LayerTypeMask, attrTableName, attrTableFilepath);
|
||||
// Layer type mask
|
||||
if (!this->disableParsedSetting(ui->spinBox_LayerTypeMask, projectConfig.getIdentifier(ProjectIdentifier::define_mask_layer), globalFieldmapPath))
|
||||
this->disableParsedSetting(ui->spinBox_LayerTypeMask, projectConfig.getIdentifier(ProjectIdentifier::define_attribute_layer), fieldmapPath);
|
||||
|
||||
// Encounter and terrain type masks
|
||||
if (project->disabledSettingsNames.contains(encounterTypeTableName))
|
||||
this->disableParsedSetting(ui->spinBox_EncounterTypeMask, attrTableName, attrTableFilepath);
|
||||
if (project->disabledSettingsNames.contains(terrainTypeTableName))
|
||||
this->disableParsedSetting(ui->spinBox_TerrainTypeMask, attrTableName, attrTableFilepath);
|
||||
}
|
||||
// Encounter and terrain type masks
|
||||
this->disableParsedSetting(ui->spinBox_EncounterTypeMask, projectConfig.getIdentifier(ProjectIdentifier::define_attribute_encounter), fieldmapPath);
|
||||
this->disableParsedSetting(ui->spinBox_TerrainTypeMask, projectConfig.getIdentifier(ProjectIdentifier::define_attribute_terrain), fieldmapPath);
|
||||
|
||||
// Tripe layer metatiles
|
||||
this->disableParsedSetting(ui->checkBox_EnableTripleLayerMetatiles, projectConfig.getIdentifier(ProjectIdentifier::define_tiles_per_metatile), constantsFieldmapPath);
|
||||
}
|
||||
|
||||
void ProjectSettingsEditor::disableParsedSetting(QWidget * widget, const QString &name, const QString &filepath) {
|
||||
widget->setEnabled(false);
|
||||
widget->setToolTip(QString("This value has been read from '%1' in %2").arg(name).arg(filepath));
|
||||
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));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remember the current settings tab for future sessions
|
||||
void ProjectSettingsEditor::on_mainTabs_tabBarClicked(int index) {
|
||||
porymapConfig.setProjectSettingsTab(index);
|
||||
porymapConfig.projectSettingsTab = index;
|
||||
}
|
||||
|
||||
void ProjectSettingsEditor::setTab(int index) {
|
||||
ui->mainTabs->setCurrentIndex(index);
|
||||
porymapConfig.setProjectSettingsTab(index);
|
||||
porymapConfig.projectSettingsTab = index;
|
||||
}
|
||||
|
||||
void ProjectSettingsEditor::setBorderMetatilesUi(bool customSize) {
|
||||
|
@ -424,10 +411,10 @@ void ProjectSettingsEditor::refresh() {
|
|||
this->refreshing = true; // Block signals
|
||||
|
||||
// Set combo box texts
|
||||
ui->comboBox_DefaultPrimaryTileset->setTextItem(projectConfig.getDefaultPrimaryTileset());
|
||||
ui->comboBox_DefaultSecondaryTileset->setTextItem(projectConfig.getDefaultSecondaryTileset());
|
||||
ui->comboBox_DefaultPrimaryTileset->setTextItem(projectConfig.defaultPrimaryTileset);
|
||||
ui->comboBox_DefaultSecondaryTileset->setTextItem(projectConfig.defaultSecondaryTileset);
|
||||
ui->comboBox_BaseGameVersion->setTextItem(projectConfig.getBaseGameVersionString());
|
||||
ui->comboBox_AttributesSize->setTextItem(QString::number(projectConfig.getMetatileAttributesSize()));
|
||||
ui->comboBox_AttributesSize->setTextItem(QString::number(projectConfig.metatileAttributesSize));
|
||||
this->updateAttributeLimits(ui->comboBox_AttributesSize->currentText());
|
||||
|
||||
this->prevIconSpecies = QString();
|
||||
|
@ -435,45 +422,44 @@ void ProjectSettingsEditor::refresh() {
|
|||
this->updatePokemonIconPath(ui->comboBox_IconSpecies->currentText());
|
||||
|
||||
// Set check box states
|
||||
ui->checkBox_UsePoryscript->setChecked(projectConfig.getUsePoryScript());
|
||||
ui->checkBox_ShowWildEncounterTables->setChecked(userConfig.getEncounterJsonActive());
|
||||
ui->checkBox_CreateTextFile->setChecked(projectConfig.getCreateMapTextFileEnabled());
|
||||
ui->checkBox_EnableTripleLayerMetatiles->setChecked(projectConfig.getTripleLayerMetatilesEnabled());
|
||||
ui->checkBox_EnableRequiresItemfinder->setChecked(projectConfig.getHiddenItemRequiresItemfinderEnabled());
|
||||
ui->checkBox_EnableQuantity->setChecked(projectConfig.getHiddenItemQuantityEnabled());
|
||||
ui->checkBox_EnableCloneObjects->setChecked(projectConfig.getEventCloneObjectEnabled());
|
||||
ui->checkBox_EnableWeatherTriggers->setChecked(projectConfig.getEventWeatherTriggerEnabled());
|
||||
ui->checkBox_EnableSecretBases->setChecked(projectConfig.getEventSecretBaseEnabled());
|
||||
ui->checkBox_EnableRespawn->setChecked(projectConfig.getHealLocationRespawnDataEnabled());
|
||||
ui->checkBox_EnableAllowFlags->setChecked(projectConfig.getMapAllowFlagsEnabled());
|
||||
ui->checkBox_EnableFloorNumber->setChecked(projectConfig.getFloorNumberEnabled());
|
||||
ui->checkBox_EnableCustomBorderSize->setChecked(projectConfig.getUseCustomBorderSize());
|
||||
ui->checkBox_OutputCallback->setChecked(projectConfig.getTilesetsHaveCallback());
|
||||
ui->checkBox_OutputIsCompressed->setChecked(projectConfig.getTilesetsHaveIsCompressed());
|
||||
ui->checkBox_DisableWarning->setChecked(porymapConfig.getWarpBehaviorWarningDisabled());
|
||||
ui->checkBox_UsePoryscript->setChecked(projectConfig.usePoryScript);
|
||||
ui->checkBox_ShowWildEncounterTables->setChecked(userConfig.useEncounterJson);
|
||||
ui->checkBox_CreateTextFile->setChecked(projectConfig.createMapTextFileEnabled);
|
||||
ui->checkBox_EnableTripleLayerMetatiles->setChecked(projectConfig.tripleLayerMetatilesEnabled);
|
||||
ui->checkBox_EnableRequiresItemfinder->setChecked(projectConfig.hiddenItemRequiresItemfinderEnabled);
|
||||
ui->checkBox_EnableQuantity->setChecked(projectConfig.hiddenItemQuantityEnabled);
|
||||
ui->checkBox_EnableCloneObjects->setChecked(projectConfig.eventCloneObjectEnabled);
|
||||
ui->checkBox_EnableWeatherTriggers->setChecked(projectConfig.eventWeatherTriggerEnabled);
|
||||
ui->checkBox_EnableSecretBases->setChecked(projectConfig.eventSecretBaseEnabled);
|
||||
ui->checkBox_EnableRespawn->setChecked(projectConfig.healLocationRespawnDataEnabled);
|
||||
ui->checkBox_EnableAllowFlags->setChecked(projectConfig.mapAllowFlagsEnabled);
|
||||
ui->checkBox_EnableFloorNumber->setChecked(projectConfig.floorNumberEnabled);
|
||||
ui->checkBox_EnableCustomBorderSize->setChecked(projectConfig.useCustomBorderSize);
|
||||
ui->checkBox_OutputCallback->setChecked(projectConfig.tilesetsHaveCallback);
|
||||
ui->checkBox_OutputIsCompressed->setChecked(projectConfig.tilesetsHaveIsCompressed);
|
||||
ui->checkBox_DisableWarning->setChecked(porymapConfig.warpBehaviorWarningDisabled);
|
||||
|
||||
// Set spin box values
|
||||
ui->spinBox_Elevation->setValue(projectConfig.getDefaultElevation());
|
||||
ui->spinBox_Collision->setValue(projectConfig.getDefaultCollision());
|
||||
ui->spinBox_FillMetatile->setValue(projectConfig.getDefaultMetatileId());
|
||||
ui->spinBox_MaxElevation->setValue(projectConfig.getCollisionSheetHeight() - 1);
|
||||
ui->spinBox_MaxCollision->setValue(projectConfig.getCollisionSheetWidth() - 1);
|
||||
ui->spinBox_BehaviorMask->setValue(projectConfig.getMetatileBehaviorMask() & ui->spinBox_BehaviorMask->maximum());
|
||||
ui->spinBox_EncounterTypeMask->setValue(projectConfig.getMetatileEncounterTypeMask() & ui->spinBox_EncounterTypeMask->maximum());
|
||||
ui->spinBox_LayerTypeMask->setValue(projectConfig.getMetatileLayerTypeMask() & ui->spinBox_LayerTypeMask->maximum());
|
||||
ui->spinBox_TerrainTypeMask->setValue(projectConfig.getMetatileTerrainTypeMask() & ui->spinBox_TerrainTypeMask->maximum());
|
||||
ui->spinBox_MetatileIdMask->setValue(projectConfig.getBlockMetatileIdMask() & ui->spinBox_MetatileIdMask->maximum());
|
||||
ui->spinBox_CollisionMask->setValue(projectConfig.getBlockCollisionMask() & ui->spinBox_CollisionMask->maximum());
|
||||
ui->spinBox_ElevationMask->setValue(projectConfig.getBlockElevationMask() & ui->spinBox_ElevationMask->maximum());
|
||||
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_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());
|
||||
ui->spinBox_TerrainTypeMask->setValue(projectConfig.metatileTerrainTypeMask & ui->spinBox_TerrainTypeMask->maximum());
|
||||
ui->spinBox_MetatileIdMask->setValue(projectConfig.blockMetatileIdMask & ui->spinBox_MetatileIdMask->maximum());
|
||||
ui->spinBox_CollisionMask->setValue(projectConfig.blockCollisionMask & ui->spinBox_CollisionMask->maximum());
|
||||
ui->spinBox_ElevationMask->setValue(projectConfig.blockElevationMask & ui->spinBox_ElevationMask->maximum());
|
||||
|
||||
// Set (and sync) border metatile IDs
|
||||
auto metatileIds = projectConfig.getNewMapBorderMetatileIds();
|
||||
this->setBorderMetatileIds(false, metatileIds);
|
||||
this->setBorderMetatileIds(true, metatileIds);
|
||||
this->setBorderMetatileIds(false, projectConfig.newMapBorderMetatileIds);
|
||||
this->setBorderMetatileIds(true, projectConfig.newMapBorderMetatileIds);
|
||||
|
||||
// Set line edit texts
|
||||
ui->lineEdit_PrefabsPath->setText(projectConfig.getPrefabFilepath());
|
||||
ui->lineEdit_CollisionGraphics->setText(projectConfig.getCollisionSheetPath());
|
||||
ui->lineEdit_PrefabsPath->setText(projectConfig.prefabFilepath);
|
||||
ui->lineEdit_CollisionGraphics->setText(projectConfig.collisionSheetPath);
|
||||
ui->lineEdit_ObjectsIcon->setText(projectConfig.getEventIconPath(Event::Group::Object));
|
||||
ui->lineEdit_WarpsIcon->setText(projectConfig.getEventIconPath(Event::Group::Warp));
|
||||
ui->lineEdit_TriggersIcon->setText(projectConfig.getEventIconPath(Event::Group::Coord));
|
||||
|
@ -485,9 +471,8 @@ void ProjectSettingsEditor::refresh() {
|
|||
lineEdit->setText(projectConfig.getCustomIdentifier(lineEdit->objectName()));
|
||||
|
||||
// Set warp behaviors
|
||||
auto behaviorValues = projectConfig.getWarpBehaviors();
|
||||
QStringList behaviorNames;
|
||||
for (auto value : behaviorValues) {
|
||||
for (auto value : projectConfig.warpBehaviors) {
|
||||
if (project->metatileBehaviorMapInverse.contains(value))
|
||||
behaviorNames.append(project->metatileBehaviorMapInverse.value(value));
|
||||
}
|
||||
|
@ -500,50 +485,47 @@ void ProjectSettingsEditor::save() {
|
|||
if (!this->hasUnsavedChanges)
|
||||
return;
|
||||
|
||||
// Prevent a call to save() for each of the config settings
|
||||
projectConfig.setSaveDisabled(true);
|
||||
|
||||
// Save combo box settings
|
||||
projectConfig.setDefaultPrimaryTileset(ui->comboBox_DefaultPrimaryTileset->currentText());
|
||||
projectConfig.setDefaultSecondaryTileset(ui->comboBox_DefaultSecondaryTileset->currentText());
|
||||
projectConfig.setBaseGameVersion(projectConfig.stringToBaseGameVersion(ui->comboBox_BaseGameVersion->currentText()));
|
||||
projectConfig.setMetatileAttributesSize(ui->comboBox_AttributesSize->currentText().toInt());
|
||||
projectConfig.defaultPrimaryTileset = ui->comboBox_DefaultPrimaryTileset->currentText();
|
||||
projectConfig.defaultSecondaryTileset = ui->comboBox_DefaultSecondaryTileset->currentText();
|
||||
projectConfig.baseGameVersion = projectConfig.stringToBaseGameVersion(ui->comboBox_BaseGameVersion->currentText());
|
||||
projectConfig.metatileAttributesSize = ui->comboBox_AttributesSize->currentText().toInt();
|
||||
|
||||
// Save check box settings
|
||||
projectConfig.setUsePoryScript(ui->checkBox_UsePoryscript->isChecked());
|
||||
userConfig.setEncounterJsonActive(ui->checkBox_ShowWildEncounterTables->isChecked());
|
||||
projectConfig.setCreateMapTextFileEnabled(ui->checkBox_CreateTextFile->isChecked());
|
||||
projectConfig.setTripleLayerMetatilesEnabled(ui->checkBox_EnableTripleLayerMetatiles->isChecked());
|
||||
projectConfig.setHiddenItemRequiresItemfinderEnabled(ui->checkBox_EnableRequiresItemfinder->isChecked());
|
||||
projectConfig.setHiddenItemQuantityEnabled(ui->checkBox_EnableQuantity->isChecked());
|
||||
projectConfig.setEventCloneObjectEnabled(ui->checkBox_EnableCloneObjects->isChecked());
|
||||
projectConfig.setEventWeatherTriggerEnabled(ui->checkBox_EnableWeatherTriggers->isChecked());
|
||||
projectConfig.setEventSecretBaseEnabled(ui->checkBox_EnableSecretBases->isChecked());
|
||||
projectConfig.setHealLocationRespawnDataEnabled(ui->checkBox_EnableRespawn->isChecked());
|
||||
projectConfig.setMapAllowFlagsEnabled(ui->checkBox_EnableAllowFlags->isChecked());
|
||||
projectConfig.setFloorNumberEnabled(ui->checkBox_EnableFloorNumber->isChecked());
|
||||
projectConfig.setUseCustomBorderSize(ui->checkBox_EnableCustomBorderSize->isChecked());
|
||||
projectConfig.setTilesetsHaveCallback(ui->checkBox_OutputCallback->isChecked());
|
||||
projectConfig.setTilesetsHaveIsCompressed(ui->checkBox_OutputIsCompressed->isChecked());
|
||||
porymapConfig.setWarpBehaviorWarningDisabled(ui->checkBox_DisableWarning->isChecked());
|
||||
projectConfig.usePoryScript = ui->checkBox_UsePoryscript->isChecked();
|
||||
userConfig.useEncounterJson = ui->checkBox_ShowWildEncounterTables->isChecked();
|
||||
projectConfig.createMapTextFileEnabled = ui->checkBox_CreateTextFile->isChecked();
|
||||
projectConfig.tripleLayerMetatilesEnabled = ui->checkBox_EnableTripleLayerMetatiles->isChecked();
|
||||
projectConfig.hiddenItemRequiresItemfinderEnabled = ui->checkBox_EnableRequiresItemfinder->isChecked();
|
||||
projectConfig.hiddenItemQuantityEnabled = ui->checkBox_EnableQuantity->isChecked();
|
||||
projectConfig.eventCloneObjectEnabled = ui->checkBox_EnableCloneObjects->isChecked();
|
||||
projectConfig.eventWeatherTriggerEnabled = ui->checkBox_EnableWeatherTriggers->isChecked();
|
||||
projectConfig.eventSecretBaseEnabled = ui->checkBox_EnableSecretBases->isChecked();
|
||||
projectConfig.healLocationRespawnDataEnabled = ui->checkBox_EnableRespawn->isChecked();
|
||||
projectConfig.mapAllowFlagsEnabled = ui->checkBox_EnableAllowFlags->isChecked();
|
||||
projectConfig.floorNumberEnabled = ui->checkBox_EnableFloorNumber->isChecked();
|
||||
projectConfig.useCustomBorderSize = ui->checkBox_EnableCustomBorderSize->isChecked();
|
||||
projectConfig.tilesetsHaveCallback = ui->checkBox_OutputCallback->isChecked();
|
||||
projectConfig.tilesetsHaveIsCompressed = ui->checkBox_OutputIsCompressed->isChecked();
|
||||
porymapConfig.warpBehaviorWarningDisabled = ui->checkBox_DisableWarning->isChecked();
|
||||
|
||||
// Save spin box settings
|
||||
projectConfig.setDefaultElevation(ui->spinBox_Elevation->value());
|
||||
projectConfig.setDefaultCollision(ui->spinBox_Collision->value());
|
||||
projectConfig.setDefaultMetatileId(ui->spinBox_FillMetatile->value());
|
||||
projectConfig.setCollisionSheetHeight(ui->spinBox_MaxElevation->value() + 1);
|
||||
projectConfig.setCollisionSheetWidth(ui->spinBox_MaxCollision->value() + 1);
|
||||
projectConfig.setMetatileBehaviorMask(ui->spinBox_BehaviorMask->value());
|
||||
projectConfig.setMetatileTerrainTypeMask(ui->spinBox_TerrainTypeMask->value());
|
||||
projectConfig.setMetatileEncounterTypeMask(ui->spinBox_EncounterTypeMask->value());
|
||||
projectConfig.setMetatileLayerTypeMask(ui->spinBox_LayerTypeMask->value());
|
||||
projectConfig.setBlockMetatileIdMask(ui->spinBox_MetatileIdMask->value());
|
||||
projectConfig.setBlockCollisionMask(ui->spinBox_CollisionMask->value());
|
||||
projectConfig.setBlockElevationMask(ui->spinBox_ElevationMask->value());
|
||||
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.metatileBehaviorMask = ui->spinBox_BehaviorMask->value();
|
||||
projectConfig.metatileTerrainTypeMask = ui->spinBox_TerrainTypeMask->value();
|
||||
projectConfig.metatileEncounterTypeMask = ui->spinBox_EncounterTypeMask->value();
|
||||
projectConfig.metatileLayerTypeMask = ui->spinBox_LayerTypeMask->value();
|
||||
projectConfig.blockMetatileIdMask = ui->spinBox_MetatileIdMask->value();
|
||||
projectConfig.blockCollisionMask = ui->spinBox_CollisionMask->value();
|
||||
projectConfig.blockElevationMask = ui->spinBox_ElevationMask->value();
|
||||
|
||||
// Save line edit settings
|
||||
projectConfig.setPrefabFilepath(ui->lineEdit_PrefabsPath->text());
|
||||
projectConfig.setCollisionSheetPath(ui->lineEdit_CollisionGraphics->text());
|
||||
projectConfig.prefabFilepath = ui->lineEdit_PrefabsPath->text();
|
||||
projectConfig.collisionSheetPath = ui->lineEdit_CollisionGraphics->text();
|
||||
projectConfig.setEventIconPath(Event::Group::Object, ui->lineEdit_ObjectsIcon->text());
|
||||
projectConfig.setEventIconPath(Event::Group::Warp, ui->lineEdit_WarpsIcon->text());
|
||||
projectConfig.setEventIconPath(Event::Group::Coord, ui->lineEdit_TriggersIcon->text());
|
||||
|
@ -555,14 +537,13 @@ void ProjectSettingsEditor::save() {
|
|||
projectConfig.setIdentifier(lineEdit->objectName(), lineEdit->text());
|
||||
|
||||
// Save warp behaviors
|
||||
projectConfig.warpBehaviors.clear();
|
||||
QStringList behaviorNames = this->getWarpBehaviorsList();
|
||||
QSet<uint32_t> behaviorValues;
|
||||
for (auto name : behaviorNames)
|
||||
behaviorValues.insert(project->metatileBehaviorMap.value(name));
|
||||
projectConfig.setWarpBehaviors(behaviorValues);
|
||||
projectConfig.warpBehaviors.insert(project->metatileBehaviorMap.value(name));
|
||||
|
||||
// Save border metatile IDs
|
||||
projectConfig.setNewMapBorderMetatileIds(this->getBorderMetatileIds(ui->checkBox_EnableCustomBorderSize->isChecked()));
|
||||
projectConfig.newMapBorderMetatileIds = this->getBorderMetatileIds(ui->checkBox_EnableCustomBorderSize->isChecked());
|
||||
|
||||
// Save pokemon icon paths
|
||||
const QString species = ui->comboBox_IconSpecies->currentText();
|
||||
|
@ -571,8 +552,10 @@ void ProjectSettingsEditor::save() {
|
|||
for (auto i = this->editedPokemonIconPaths.cbegin(), end = this->editedPokemonIconPaths.cend(); i != end; i++)
|
||||
projectConfig.setPokemonIconPath(i.key(), i.value());
|
||||
|
||||
projectConfig.setSaveDisabled(false);
|
||||
projectConfig.save();
|
||||
userConfig.save();
|
||||
porymapConfig.save();
|
||||
|
||||
this->hasUnsavedChanges = false;
|
||||
|
||||
// Technically, a reload is not required for several of the config settings.
|
||||
|
@ -611,7 +594,7 @@ void ProjectSettingsEditor::importDefaultPrefabsClicked(bool) {
|
|||
// If the prompt is accepted the prefabs file will be created and its filepath will be saved in the config.
|
||||
BaseGameVersion version = projectConfig.stringToBaseGameVersion(ui->comboBox_BaseGameVersion->currentText());
|
||||
if (prefab.tryImportDefaultPrefabs(this, version, ui->lineEdit_PrefabsPath->text())) {
|
||||
ui->lineEdit_PrefabsPath->setText(projectConfig.getPrefabFilepath()); // Refresh with new filepath
|
||||
ui->lineEdit_PrefabsPath->setText(projectConfig.prefabFilepath); // Refresh with new filepath
|
||||
this->hasUnsavedChanges = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,11 @@ RegionMapEditor::RegionMapEditor(QWidget *parent, Project *project) :
|
|||
QMainWindow(parent),
|
||||
ui(new Ui::RegionMapEditor)
|
||||
{
|
||||
this->setAttribute(Qt::WA_DeleteOnClose);
|
||||
this->ui->setupUi(this);
|
||||
this->project = project;
|
||||
this->configFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg));
|
||||
this->mapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
|
||||
this->initShortcuts();
|
||||
this->restoreWindowState();
|
||||
}
|
||||
|
@ -110,12 +113,10 @@ void RegionMapEditor::applyUserShortcuts() {
|
|||
bool RegionMapEditor::loadRegionMapEntries() {
|
||||
this->region_map_entries.clear();
|
||||
|
||||
QString regionMapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
|
||||
|
||||
ParseUtil parser;
|
||||
QJsonDocument sectionsDoc;
|
||||
if (!parser.tryParseJsonFile(§ionsDoc, regionMapSectionFilepath)) {
|
||||
logError(QString("Failed to read map data from %1").arg(regionMapSectionFilepath));
|
||||
if (!parser.tryParseJsonFile(§ionsDoc, this->mapSectionFilepath)) {
|
||||
logError(QString("Failed to read map data from %1").arg(this->mapSectionFilepath));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -140,11 +141,9 @@ bool RegionMapEditor::loadRegionMapEntries() {
|
|||
}
|
||||
|
||||
bool RegionMapEditor::saveRegionMapEntries() {
|
||||
QString regionMapSectionFilepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_map_entries));
|
||||
|
||||
QFile sectionsFile(regionMapSectionFilepath);
|
||||
QFile sectionsFile(this->mapSectionFilepath);
|
||||
if (!sectionsFile.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Error: Could not open %1 for writing").arg(regionMapSectionFilepath));
|
||||
logError(QString("Could not open %1 for writing").arg(this->mapSectionFilepath));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -203,18 +202,18 @@ void buildFireredDefaults(poryjson::Json &json) {
|
|||
|
||||
poryjson::Json RegionMapEditor::buildDefaultJson() {
|
||||
poryjson::Json defaultJson;
|
||||
switch (projectConfig.getBaseGameVersion()) {
|
||||
switch (projectConfig.baseGameVersion) {
|
||||
case BaseGameVersion::pokeemerald:
|
||||
buildEmeraldDefaults(defaultJson);
|
||||
break;
|
||||
|
||||
case BaseGameVersion::pokeruby:
|
||||
buildRubyDefaults(defaultJson);
|
||||
break;
|
||||
|
||||
case BaseGameVersion::pokefirered:
|
||||
buildFireredDefaults(defaultJson);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return defaultJson;
|
||||
|
@ -298,7 +297,7 @@ bool RegionMapEditor::buildConfigDialog() {
|
|||
form.addRow(addMapButton);
|
||||
|
||||
// allow user to add region maps
|
||||
connect(addMapButton, &QPushButton::clicked, [this, regionMapList] {
|
||||
connect(addMapButton, &QPushButton::clicked, [this, regionMapList, &updateJsonFromList] {
|
||||
poryjson::Json resultJson = configRegionMapDialog();
|
||||
poryjson::Json::object resultObj = resultJson.object_items();
|
||||
|
||||
|
@ -310,12 +309,13 @@ bool RegionMapEditor::buildConfigDialog() {
|
|||
newItem->setText(resultObj["alias"].string_value());
|
||||
newItem->setData(Qt::UserRole, resultStr);
|
||||
regionMapList->addItem(newItem);
|
||||
updateJsonFromList();
|
||||
});
|
||||
|
||||
QPushButton *delMapButton = new QPushButton("Delete Selected Region Map");
|
||||
form.addRow(delMapButton);
|
||||
|
||||
connect(delMapButton, &QPushButton::clicked, [this, regionMapList, &updateJsonFromList] {
|
||||
connect(delMapButton, &QPushButton::clicked, [regionMapList, &updateJsonFromList] {
|
||||
QListWidgetItem *item = regionMapList->currentItem();
|
||||
if (item) {
|
||||
regionMapList->removeItemWidget(item);
|
||||
|
@ -344,8 +344,8 @@ bool RegionMapEditor::buildConfigDialog() {
|
|||
|
||||
|
||||
// for sake of convenience, option to just use defaults for each basegame version
|
||||
QPushButton *config_useProjectDefault;
|
||||
switch (projectConfig.getBaseGameVersion()) {
|
||||
QPushButton *config_useProjectDefault = nullptr;
|
||||
switch (projectConfig.baseGameVersion) {
|
||||
case BaseGameVersion::pokefirered:
|
||||
config_useProjectDefault = new QPushButton("\nUse pokefirered defaults\n");
|
||||
break;
|
||||
|
@ -403,16 +403,6 @@ bool RegionMapEditor::verifyConfig(poryjson::Json cfg) {
|
|||
logError("Region map config json has no map list.");
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderedJson::array arr = obj["region_maps"].array_items();
|
||||
|
||||
for (auto ref : arr) {
|
||||
RegionMap tempMap(this->project);
|
||||
if (!tempMap.loadMapData(ref)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -476,6 +466,7 @@ bool RegionMapEditor::setup() {
|
|||
if (!newMap->loadMapData(o)) {
|
||||
delete newMap;
|
||||
// TODO: consider continue, just reporting error loading single map?
|
||||
this->setupError = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -498,26 +489,21 @@ bool RegionMapEditor::setup() {
|
|||
if (!region_maps.empty()) {
|
||||
setRegionMap(region_maps.begin()->second);
|
||||
}
|
||||
this->setupError = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RegionMapEditor::load(bool silent) {
|
||||
// check for config json file
|
||||
QString jsonConfigFilepath = this->project->root + "/" + projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg);
|
||||
|
||||
bool badConfig = true;
|
||||
|
||||
if (QFile::exists(jsonConfigFilepath)) {
|
||||
logInfo("Region map configuration file found.");
|
||||
if (QFile::exists(this->configFilepath)) {
|
||||
ParseUtil parser;
|
||||
OrderedJson::object obj;
|
||||
if (parser.tryParseOrderedJsonFile(&obj, jsonConfigFilepath)) {
|
||||
if (parser.tryParseOrderedJsonFile(&obj, this->configFilepath)) {
|
||||
this->rmConfigJson = OrderedJson(obj);
|
||||
this->configSaved = true;
|
||||
}
|
||||
badConfig = !verifyConfig(this->rmConfigJson);
|
||||
} else {
|
||||
logWarn("Region Map config file not found.");
|
||||
}
|
||||
|
||||
if (badConfig) {
|
||||
|
@ -533,14 +519,15 @@ bool RegionMapEditor::load(bool silent) {
|
|||
if (warning.exec() == QMessageBox::Ok) {
|
||||
// there is a separate window that allows to load multiple region maps,
|
||||
if (!buildConfigDialog()) {
|
||||
logError("Region map loading interrupted [user]");
|
||||
// User canceled config set up
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// do not open editor
|
||||
logError("Region map loading interrupted [user]");
|
||||
// User declined config set up
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
logInfo("Successfully loaded region map configuration file.");
|
||||
}
|
||||
|
||||
return setup();
|
||||
|
@ -582,10 +569,9 @@ void RegionMapEditor::saveConfig() {
|
|||
mapsObject["region_maps"] = mapArray;
|
||||
|
||||
OrderedJson newConfigJson(mapsObject);
|
||||
QString filepath = QString("%1/%2").arg(this->project->root).arg(projectConfig.getFilePath(ProjectFilePath::json_region_porymap_cfg));
|
||||
QFile file(filepath);
|
||||
QFile file(this->configFilepath);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
logError(QString("Error: Could not open %1 for writing").arg(filepath));
|
||||
logError(QString("Could not open %1 for writing").arg(this->configFilepath));
|
||||
return;
|
||||
}
|
||||
OrderedJsonDoc jsonDoc(&newConfigJson);
|
||||
|
@ -614,6 +600,11 @@ void RegionMapEditor::on_actionSave_All_triggered() {
|
|||
}
|
||||
|
||||
void RegionMapEditor::on_action_Configure_triggered() {
|
||||
reconfigure();
|
||||
}
|
||||
|
||||
bool RegionMapEditor::reconfigure() {
|
||||
this->setupError = false;
|
||||
if (this->modified()) {
|
||||
QMessageBox warning;
|
||||
warning.setIcon(QMessageBox::Warning);
|
||||
|
@ -624,15 +615,16 @@ void RegionMapEditor::on_action_Configure_triggered() {
|
|||
|
||||
if (warning.exec() == QMessageBox::Ok) {
|
||||
if (buildConfigDialog()) {
|
||||
reload();
|
||||
return reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (buildConfigDialog()) {
|
||||
reload();
|
||||
return reload();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RegionMapEditor::displayRegionMap() {
|
||||
|
|
|
@ -53,6 +53,7 @@ void ShortcutsEditor::saveShortcuts() {
|
|||
}
|
||||
|
||||
shortcutsConfig.setUserShortcuts(objects_keySequences);
|
||||
shortcutsConfig.save();
|
||||
emit shortcutsSaved();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ TilesetEditor::TilesetEditor(Project *project, Layout *layout, QWidget *parent)
|
|||
layout(layout),
|
||||
hasUnsavedChanges(false)
|
||||
{
|
||||
this->setAttribute(Qt::WA_DeleteOnClose);
|
||||
this->setTilesets(this->layout->tileset_primary_label, this->layout->tileset_secondary_label);
|
||||
this->initUi();
|
||||
}
|
||||
|
@ -113,7 +114,7 @@ void TilesetEditor::initUi() {
|
|||
|
||||
void TilesetEditor::setAttributesUi() {
|
||||
// Behavior
|
||||
if (projectConfig.getMetatileBehaviorMask()) {
|
||||
if (projectConfig.metatileBehaviorMask) {
|
||||
for (int num : project->metatileBehaviorMapInverse.keys()) {
|
||||
this->ui->comboBox_metatileBehaviors->addItem(project->metatileBehaviorMapInverse[num], num);
|
||||
}
|
||||
|
@ -124,7 +125,7 @@ void TilesetEditor::setAttributesUi() {
|
|||
}
|
||||
|
||||
// Terrain Type
|
||||
if (projectConfig.getMetatileTerrainTypeMask()) {
|
||||
if (projectConfig.metatileTerrainTypeMask) {
|
||||
this->ui->comboBox_terrainType->addItem("Normal", TERRAIN_NONE);
|
||||
this->ui->comboBox_terrainType->addItem("Grass", TERRAIN_GRASS);
|
||||
this->ui->comboBox_terrainType->addItem("Water", TERRAIN_WATER);
|
||||
|
@ -137,7 +138,7 @@ void TilesetEditor::setAttributesUi() {
|
|||
}
|
||||
|
||||
// Encounter Type
|
||||
if (projectConfig.getMetatileEncounterTypeMask()) {
|
||||
if (projectConfig.metatileEncounterTypeMask) {
|
||||
this->ui->comboBox_encounterType->addItem("None", ENCOUNTER_NONE);
|
||||
this->ui->comboBox_encounterType->addItem("Land", ENCOUNTER_LAND);
|
||||
this->ui->comboBox_encounterType->addItem("Water", ENCOUNTER_WATER);
|
||||
|
@ -149,13 +150,13 @@ void TilesetEditor::setAttributesUi() {
|
|||
}
|
||||
|
||||
// Layer Type
|
||||
if (!projectConfig.getTripleLayerMetatilesEnabled()) {
|
||||
if (!projectConfig.tripleLayerMetatilesEnabled) {
|
||||
this->ui->comboBox_layerType->addItem("Normal - Middle/Top", METATILE_LAYER_MIDDLE_TOP);
|
||||
this->ui->comboBox_layerType->addItem("Covered - Bottom/Middle", METATILE_LAYER_BOTTOM_MIDDLE);
|
||||
this->ui->comboBox_layerType->addItem("Split - Bottom/Top", METATILE_LAYER_BOTTOM_TOP);
|
||||
this->ui->comboBox_layerType->setEditable(false);
|
||||
this->ui->comboBox_layerType->setMinimumContentsLength(0);
|
||||
if (!projectConfig.getMetatileLayerTypeMask()) {
|
||||
if (!projectConfig.metatileLayerTypeMask) {
|
||||
// User doesn't have triple layer metatiles, but has no layer type attribute.
|
||||
// Porymap is still using the layer type value to render metatiles, and with
|
||||
// no mask set every metatile will be "Middle/Top", so just display the combo
|
||||
|
@ -187,7 +188,7 @@ void TilesetEditor::initMetatileSelector()
|
|||
connect(this->metatileSelector, &TilesetEditorMetatileSelector::selectedMetatileChanged,
|
||||
this, &TilesetEditor::onSelectedMetatileChanged);
|
||||
|
||||
bool showGrid = porymapConfig.getShowTilesetEditorMetatileGrid();
|
||||
bool showGrid = porymapConfig.showTilesetEditorMetatileGrid;
|
||||
this->ui->actionMetatile_Grid->setChecked(showGrid);
|
||||
this->metatileSelector->showGrid = showGrid;
|
||||
|
||||
|
@ -197,7 +198,7 @@ void TilesetEditor::initMetatileSelector()
|
|||
|
||||
this->ui->graphicsView_Metatiles->setScene(this->metatilesScene);
|
||||
this->ui->graphicsView_Metatiles->setResizeAnchor(QGraphicsView::AnchorViewCenter);
|
||||
this->ui->horizontalSlider_MetatilesZoom->setValue(porymapConfig.getTilesetEditorMetatilesZoom());
|
||||
this->ui->horizontalSlider_MetatilesZoom->setValue(porymapConfig.tilesetEditorMetatilesZoom);
|
||||
}
|
||||
|
||||
void TilesetEditor::initMetatileLayersItem() {
|
||||
|
@ -212,7 +213,7 @@ void TilesetEditor::initMetatileLayersItem() {
|
|||
connect(this->metatileLayersItem, &MetatileLayersItem::hoveredTileCleared,
|
||||
this, &TilesetEditor::onHoveredTileCleared);
|
||||
|
||||
bool showGrid = porymapConfig.getShowTilesetEditorLayerGrid();
|
||||
bool showGrid = porymapConfig.showTilesetEditorLayerGrid;
|
||||
this->ui->actionLayer_Grid->setChecked(showGrid);
|
||||
this->metatileLayersItem->showGrid = showGrid;
|
||||
|
||||
|
@ -238,7 +239,7 @@ void TilesetEditor::initTileSelector()
|
|||
|
||||
this->ui->graphicsView_Tiles->setScene(this->tilesScene);
|
||||
this->ui->graphicsView_Tiles->setResizeAnchor(QGraphicsView::AnchorViewCenter);
|
||||
this->ui->horizontalSlider_TilesZoom->setValue(porymapConfig.getTilesetEditorTilesZoom());
|
||||
this->ui->horizontalSlider_TilesZoom->setValue(porymapConfig.tilesetEditorTilesZoom);
|
||||
}
|
||||
|
||||
void TilesetEditor::initSelectedTileItem() {
|
||||
|
@ -1069,13 +1070,13 @@ void TilesetEditor::on_actionShow_UnusedTiles_toggled(bool checked) {
|
|||
void TilesetEditor::on_actionMetatile_Grid_triggered(bool checked) {
|
||||
this->metatileSelector->showGrid = checked;
|
||||
this->metatileSelector->draw();
|
||||
porymapConfig.setShowTilesetEditorMetatileGrid(checked);
|
||||
porymapConfig.showTilesetEditorMetatileGrid = checked;
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionLayer_Grid_triggered(bool checked) {
|
||||
this->metatileLayersItem->showGrid = checked;
|
||||
this->metatileLayersItem->draw();
|
||||
porymapConfig.setShowTilesetEditorLayerGrid(checked);
|
||||
porymapConfig.showTilesetEditorLayerGrid = checked;
|
||||
}
|
||||
|
||||
void TilesetEditor::countMetatileUsage() {
|
||||
|
@ -1187,7 +1188,7 @@ void TilesetEditor::on_copyButton_metatileLabel_clicked() {
|
|||
}
|
||||
|
||||
void TilesetEditor::on_horizontalSlider_MetatilesZoom_valueChanged(int value) {
|
||||
porymapConfig.setTilesetEditorMetatilesZoom(value);
|
||||
porymapConfig.tilesetEditorMetatilesZoom = value;
|
||||
this->redrawMetatileSelector();
|
||||
}
|
||||
|
||||
|
@ -1195,7 +1196,7 @@ void TilesetEditor::redrawMetatileSelector() {
|
|||
QSize size(this->metatileSelector->pixmap().width(), this->metatileSelector->pixmap().height());
|
||||
this->ui->graphicsView_Metatiles->setSceneRect(0, 0, size.width(), size.height());
|
||||
|
||||
double scale = pow(3.0, static_cast<double>(porymapConfig.getTilesetEditorMetatilesZoom() - 30) / 30.0);
|
||||
double scale = pow(3.0, static_cast<double>(porymapConfig.tilesetEditorMetatilesZoom - 30) / 30.0);
|
||||
QTransform transform;
|
||||
transform.scale(scale, scale);
|
||||
size *= scale;
|
||||
|
@ -1212,7 +1213,7 @@ void TilesetEditor::redrawMetatileSelector() {
|
|||
}
|
||||
|
||||
void TilesetEditor::on_horizontalSlider_TilesZoom_valueChanged(int value) {
|
||||
porymapConfig.setTilesetEditorTilesZoom(value);
|
||||
porymapConfig.tilesetEditorTilesZoom = value;
|
||||
this->redrawTileSelector();
|
||||
}
|
||||
|
||||
|
@ -1220,7 +1221,7 @@ void TilesetEditor::redrawTileSelector() {
|
|||
QSize size(this->tileSelector->pixmap().width(), this->tileSelector->pixmap().height());
|
||||
this->ui->graphicsView_Tiles->setSceneRect(0, 0, size.width(), size.height());
|
||||
|
||||
double scale = pow(3.0, static_cast<double>(porymapConfig.getTilesetEditorTilesZoom() - 30) / 30.0);
|
||||
double scale = pow(3.0, static_cast<double>(porymapConfig.tilesetEditorTilesZoom - 30) / 30.0);
|
||||
QTransform transform;
|
||||
transform.scale(scale, scale);
|
||||
size *= scale;
|
||||
|
|
|
@ -20,8 +20,7 @@ UpdatePromoter::UpdatePromoter(QWidget *parent, NetworkAccessManager *manager)
|
|||
this->updatePreferences();
|
||||
ui->checkBox_StopAlerts->setVisible(false);
|
||||
connect(ui->checkBox_StopAlerts, &QCheckBox::stateChanged, [this](int state) {
|
||||
bool enable = (state != Qt::Checked);
|
||||
porymapConfig.setCheckForUpdates(enable);
|
||||
porymapConfig.checkForUpdates = (state != Qt::Checked);
|
||||
emit this->changedPreferences();
|
||||
});
|
||||
|
||||
|
@ -141,11 +140,11 @@ void UpdatePromoter::processWebpage(const QJsonDocument &data, const QUrl &nextU
|
|||
// Alert the user about the new version if the dialog wasn't already open.
|
||||
// Show the window, but also show the option to turn off automatic alerts in the future.
|
||||
// We only show this alert once for a given release.
|
||||
if (!this->isVisible() && this->newVersion > porymapConfig.getLastUpdateCheckVersion()) {
|
||||
if (!this->isVisible() && this->newVersion > porymapConfig.lastUpdateCheckVersion) {
|
||||
ui->checkBox_StopAlerts->setVisible(true);
|
||||
this->show();
|
||||
}
|
||||
porymapConfig.setLastUpdateCheckVersion(this->newVersion);
|
||||
porymapConfig.lastUpdateCheckVersion = this->newVersion;
|
||||
} else {
|
||||
ui->label_Status->setText("Your version of Porymap is up to date!");
|
||||
ui->label_Warning->setVisible(false);
|
||||
|
@ -173,7 +172,7 @@ void UpdatePromoter::error(const QString &err, const QDateTime retryAfter) {
|
|||
|
||||
void UpdatePromoter::updatePreferences() {
|
||||
const QSignalBlocker blocker(ui->checkBox_StopAlerts);
|
||||
ui->checkBox_StopAlerts->setChecked(!porymapConfig.getCheckForUpdates());
|
||||
ui->checkBox_StopAlerts->setChecked(!porymapConfig.checkForUpdates);
|
||||
}
|
||||
|
||||
void UpdatePromoter::dialogButtonClicked(QAbstractButton *button) {
|
||||
|
|
452
src/ui/wildmonchart.cpp
Normal file
452
src/ui/wildmonchart.cpp
Normal file
|
@ -0,0 +1,452 @@
|
|||
#if __has_include(<QtCharts>)
|
||||
#include "wildmonchart.h"
|
||||
#include "ui_wildmonchart.h"
|
||||
#include "config.h"
|
||||
|
||||
static const QString baseWindowTitle = QString("Wild Pokémon Summary Charts");
|
||||
|
||||
static const QList<QPair<QString, QChart::ChartTheme>> themes = {
|
||||
{"Light", QChart::ChartThemeLight},
|
||||
{"Dark", QChart::ChartThemeDark},
|
||||
{"Blue Cerulean", QChart::ChartThemeBlueCerulean},
|
||||
{"Brown Sand", QChart::ChartThemeBrownSand},
|
||||
{"Blue NCS", QChart::ChartThemeBlueNcs},
|
||||
{"High Contrast", QChart::ChartThemeHighContrast},
|
||||
{"Blue Icy", QChart::ChartThemeBlueIcy},
|
||||
{"Qt", QChart::ChartThemeQt},
|
||||
};
|
||||
|
||||
WildMonChart::WildMonChart(QWidget *parent, const EncounterTableModel *table) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::WildMonChart)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setWindowFlags(Qt::Window);
|
||||
|
||||
connect(ui->button_Help, &QAbstractButton::clicked, this, &WildMonChart::showHelpDialog);
|
||||
|
||||
// Changing these settings changes which level distribution chart is shown
|
||||
connect(ui->groupBox_Species, &QGroupBox::clicked, this, &WildMonChart::refreshLevelDistributionChart);
|
||||
connect(ui->comboBox_Species, &QComboBox::currentTextChanged, this, &WildMonChart::refreshLevelDistributionChart);
|
||||
connect(ui->comboBox_Group, &QComboBox::currentTextChanged, this, &WildMonChart::refreshLevelDistributionChart);
|
||||
|
||||
// Set up Theme combo box
|
||||
for (auto i : themes)
|
||||
ui->comboBox_Theme->addItem(i.first, i.second);
|
||||
connect(ui->comboBox_Theme, &QComboBox::currentTextChanged, this, &WildMonChart::updateTheme);
|
||||
|
||||
// User's theme choice is saved in the config
|
||||
int configThemeIndex = ui->comboBox_Theme->findText(porymapConfig.wildMonChartTheme);
|
||||
if (configThemeIndex >= 0) {
|
||||
const QSignalBlocker blocker(ui->comboBox_Theme);
|
||||
ui->comboBox_Theme->setCurrentIndex(configThemeIndex);
|
||||
} else {
|
||||
porymapConfig.wildMonChartTheme = ui->comboBox_Theme->currentText();
|
||||
}
|
||||
|
||||
restoreGeometry(porymapConfig.wildMonChartGeometry);
|
||||
|
||||
setTable(table);
|
||||
};
|
||||
|
||||
WildMonChart::~WildMonChart() {
|
||||
delete ui;
|
||||
};
|
||||
|
||||
void WildMonChart::setTable(const EncounterTableModel *table) {
|
||||
if (this->table == table)
|
||||
return;
|
||||
this->table = table;
|
||||
refresh();
|
||||
}
|
||||
|
||||
void WildMonChart::clearTable() {
|
||||
setTable(nullptr);
|
||||
}
|
||||
|
||||
void WildMonChart::clearTableData() {
|
||||
this->groupNames.clear();
|
||||
this->groupNamesReversed.clear();
|
||||
this->speciesInLegendOrder.clear();
|
||||
this->tableIndexToGroupName.clear();
|
||||
this->groupedLevelRanges.clear();
|
||||
this->speciesToGroupedData.clear();
|
||||
this->speciesToColor.clear();
|
||||
setWindowTitle(baseWindowTitle);
|
||||
|
||||
const QSignalBlocker blocker1(ui->comboBox_Species);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Group);
|
||||
ui->comboBox_Species->clear();
|
||||
ui->comboBox_Group->clear();
|
||||
ui->comboBox_Group->setEnabled(false);
|
||||
}
|
||||
|
||||
// Extract all the data from the table that we need for the charts
|
||||
void WildMonChart::readTable() {
|
||||
clearTableData();
|
||||
if (!this->table)
|
||||
return;
|
||||
|
||||
setWindowTitle(QString("%1 - %2").arg(baseWindowTitle).arg(this->table->encounterField().name));
|
||||
|
||||
// Read data about encounter groups, e.g. for "fishing_mons" we want to know table indexes 2-4 belong to "good_rod"
|
||||
for (auto groupPair : this->table->encounterField().groups) {
|
||||
// Frustratingly when adding categories to the charts they insert bottom-to-top, but the table and combo box
|
||||
// insert top-to-bottom. To keep the order visually the same across displays we keep separate ordered lists.
|
||||
this->groupNames.append(groupPair.first);
|
||||
this->groupNamesReversed.prepend(groupPair.first);
|
||||
for (auto i : groupPair.second)
|
||||
this->tableIndexToGroupName.insert(i, groupPair.first);
|
||||
}
|
||||
// Implicitly 1 unnamed group when none are listed
|
||||
if (this->groupNames.isEmpty()) {
|
||||
this->groupNames.append(QString());
|
||||
this->groupNamesReversed.append(QString());
|
||||
}
|
||||
|
||||
// Read data from the table, combining data for duplicate entries
|
||||
const QList<double> tableFrequencies = this->table->percentages();
|
||||
const QVector<WildPokemon> tablePokemon = this->table->encounterData().wildPokemon;
|
||||
const int numRows = qMin(tableFrequencies.length(), tablePokemon.length());
|
||||
const QString speciesPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_species_prefix);
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
const double frequency = tableFrequencies.at(i);
|
||||
const WildPokemon pokemon = tablePokemon.at(i);
|
||||
const QString groupName = this->tableIndexToGroupName.value(i);
|
||||
|
||||
// Create species label (strip 'SPECIES_' prefix).
|
||||
QString label = pokemon.species;
|
||||
if (label.startsWith(speciesPrefix))
|
||||
label.remove(0, speciesPrefix.length());
|
||||
|
||||
// Add species/level frequency data
|
||||
Summary *summary = &this->speciesToGroupedData[label][groupName];
|
||||
summary->speciesFrequency += frequency;
|
||||
if (pokemon.minLevel > pokemon.maxLevel)
|
||||
continue; // Invalid
|
||||
int numLevels = pokemon.maxLevel - pokemon.minLevel + 1;
|
||||
for (int level = pokemon.minLevel; level <= pokemon.maxLevel; level++)
|
||||
summary->levelFrequencies[level] += frequency / numLevels;
|
||||
|
||||
// Update level min/max for showing level distribution across a group
|
||||
if (!this->groupedLevelRanges.contains(groupName)) {
|
||||
LevelRange *levelRange = &this->groupedLevelRanges[groupName];
|
||||
levelRange->min = pokemon.minLevel;
|
||||
levelRange->max = pokemon.maxLevel;
|
||||
} else {
|
||||
LevelRange *levelRange = &this->groupedLevelRanges[groupName];
|
||||
if (levelRange->min > pokemon.minLevel)
|
||||
levelRange->min = pokemon.minLevel;
|
||||
if (levelRange->max < pokemon.maxLevel)
|
||||
levelRange->max = pokemon.maxLevel;
|
||||
}
|
||||
}
|
||||
|
||||
// Populate combo boxes
|
||||
const QSignalBlocker blocker1(ui->comboBox_Species);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Group);
|
||||
ui->comboBox_Species->clear();
|
||||
ui->comboBox_Species->addItems(getSpeciesNamesAlphabetical());
|
||||
ui->comboBox_Group->clear();
|
||||
ui->comboBox_Group->addItems(this->groupNames);
|
||||
ui->comboBox_Group->setEnabled(usesGroupLabels());
|
||||
}
|
||||
|
||||
void WildMonChart::refresh() {
|
||||
const QSignalBlocker blocker1(ui->comboBox_Species);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Group);
|
||||
const QString oldSpecies = ui->comboBox_Species->currentText();
|
||||
const QString oldGroup = ui->comboBox_Group->currentText();
|
||||
|
||||
readTable();
|
||||
|
||||
// If the old UI settings are still valid we should restore them
|
||||
int index = ui->comboBox_Species->findText(oldSpecies);
|
||||
if (index >= 0) ui->comboBox_Species->setCurrentIndex(index);
|
||||
|
||||
index = ui->comboBox_Group->findText(oldGroup);
|
||||
if (index >= 0) ui->comboBox_Group->setCurrentIndex(index);
|
||||
|
||||
refreshSpeciesDistributionChart();
|
||||
refreshLevelDistributionChart();
|
||||
}
|
||||
|
||||
void WildMonChart::refreshSpeciesDistributionChart() {
|
||||
if (ui->chartView_SpeciesDistribution->chart())
|
||||
ui->chartView_SpeciesDistribution->chart()->deleteLater();
|
||||
ui->chartView_SpeciesDistribution->setChart(createSpeciesDistributionChart());
|
||||
limitChartAnimation(ui->chartView_SpeciesDistribution->chart());
|
||||
}
|
||||
|
||||
void WildMonChart::refreshLevelDistributionChart() {
|
||||
if (ui->chartView_LevelDistribution->chart())
|
||||
ui->chartView_LevelDistribution->chart()->deleteLater();
|
||||
ui->chartView_LevelDistribution->setChart(createLevelDistributionChart());
|
||||
limitChartAnimation(ui->chartView_LevelDistribution->chart());
|
||||
}
|
||||
|
||||
QStringList WildMonChart::getSpeciesNamesAlphabetical() const {
|
||||
return this->speciesToGroupedData.keys();
|
||||
}
|
||||
|
||||
double WildMonChart::getSpeciesFrequency(const QString &species, const QString &groupName) const {
|
||||
return this->speciesToGroupedData[species][groupName].speciesFrequency;
|
||||
}
|
||||
|
||||
QMap<int, double> WildMonChart::getLevelFrequencies(const QString &species, const QString &groupName) const {
|
||||
return this->speciesToGroupedData[species][groupName].levelFrequencies;
|
||||
}
|
||||
|
||||
WildMonChart::LevelRange WildMonChart::getLevelRange(const QString &species, const QString &groupName) const {
|
||||
const QList<int> levels = getLevelFrequencies(species, groupName).keys();
|
||||
|
||||
LevelRange range;
|
||||
if (levels.isEmpty()) {
|
||||
range.min = 0;
|
||||
range.max = 0;
|
||||
} else {
|
||||
range.min = levels.first();
|
||||
range.max = levels.last();
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
bool WildMonChart::usesGroupLabels() const {
|
||||
return this->groupNames.length() > 1;
|
||||
}
|
||||
|
||||
QChart* WildMonChart::createSpeciesDistributionChart() {
|
||||
QList<QBarSet*> barSets;
|
||||
for (const auto species : getSpeciesNamesAlphabetical()) {
|
||||
// Add encounter chance data
|
||||
auto set = new QBarSet(species);
|
||||
for (auto groupName : this->groupNamesReversed)
|
||||
set->append(getSpeciesFrequency(species, groupName) * 100);
|
||||
|
||||
// We order the bar sets from lowest to highest total, left-to-right.
|
||||
for (int i = 0; i < barSets.length() + 1; i++){
|
||||
if (i >= barSets.length() || barSets.at(i)->sum() > set->sum()) {
|
||||
barSets.insert(i, set);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Show species name and % when hovering over a bar set. This covers some shortfalls in our ability to control the chart design
|
||||
// (i.e. bar segments may be too narrow to see the % label, or colors may be hard to match to the legend).
|
||||
connect(set, &QBarSet::hovered, [set] (bool on, int i) {
|
||||
QString text = on ? QString("%1 (%2%)").arg(set->label()).arg(set->at(i)) : "";
|
||||
QToolTip::showText(QCursor::pos(), text);
|
||||
});
|
||||
}
|
||||
|
||||
// Preserve the order we set earlier so that the legend isn't shuffling around for the other all-species charts.
|
||||
this->speciesInLegendOrder.clear();
|
||||
for (auto set : barSets)
|
||||
this->speciesInLegendOrder.append(set->label());
|
||||
|
||||
// Set up series
|
||||
auto series = new QHorizontalPercentBarSeries();
|
||||
series->setLabelsVisible();
|
||||
series->append(barSets);
|
||||
|
||||
// Set up chart
|
||||
auto chart = new QChart();
|
||||
chart->addSeries(series);
|
||||
chart->setTheme(currentTheme());
|
||||
chart->setAnimationOptions(QChart::SeriesAnimations);
|
||||
chart->legend()->setVisible(true);
|
||||
chart->legend()->setShowToolTips(true);
|
||||
chart->legend()->setAlignment(Qt::AlignBottom);
|
||||
saveSpeciesColors(barSets);
|
||||
|
||||
// X-axis is the % frequency. We're already showing percentages on the bar, so we just display 0/50/100%
|
||||
auto axisX = new QValueAxis();
|
||||
axisX->setLabelFormat("%u%%");
|
||||
axisX->setTickCount(3);
|
||||
chart->addAxis(axisX, Qt::AlignBottom);
|
||||
series->attachAxis(axisX);
|
||||
|
||||
// Y-axis is the names of encounter groups (e.g. Old Rod, Good Rod...)
|
||||
if (usesGroupLabels()) {
|
||||
auto axisY = new QBarCategoryAxis();
|
||||
axisY->setCategories(this->groupNamesReversed);
|
||||
chart->addAxis(axisY, Qt::AlignLeft);
|
||||
series->attachAxis(axisY);
|
||||
}
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
QBarSet* WildMonChart::createLevelDistributionBarSet(const QString &species, const QString &groupName, bool individual) {
|
||||
const double totalFrequency = individual ? getSpeciesFrequency(species, groupName) : 1.0;
|
||||
const QMap<int, double> levelFrequencies = getLevelFrequencies(species, groupName);
|
||||
|
||||
auto set = new QBarSet(species);
|
||||
LevelRange levelRange = individual ? getLevelRange(species, groupName) : this->groupedLevelRanges.value(groupName);
|
||||
for (int i = levelRange.min; i <= levelRange.max; i++) {
|
||||
set->append(levelFrequencies.value(i, 0) / totalFrequency * 100);
|
||||
}
|
||||
|
||||
// Show data when hovering over a bar set. This covers some shortfalls in our ability to control the chart design.
|
||||
connect(set, &QBarSet::hovered, [=] (bool on, int i) {
|
||||
QString text = on ? QString("%1 Lv%2 (%3%)")
|
||||
.arg(individual ? "" : set->label())
|
||||
.arg(QString::number(i + levelRange.min))
|
||||
.arg(set->at(i))
|
||||
: "";
|
||||
QToolTip::showText(QCursor::pos(), text);
|
||||
});
|
||||
|
||||
// Clicking on a bar set in the stacked chart opens its individual chart
|
||||
if (!individual) {
|
||||
connect(set, &QBarSet::clicked, [this, species](int) {
|
||||
const QSignalBlocker blocker1(ui->groupBox_Species);
|
||||
const QSignalBlocker blocker2(ui->comboBox_Species);
|
||||
ui->groupBox_Species->setChecked(true);
|
||||
ui->comboBox_Species->setCurrentText(species);
|
||||
refreshLevelDistributionChart();
|
||||
});
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
QChart* WildMonChart::createLevelDistributionChart() {
|
||||
const QString groupName = ui->comboBox_Group->currentText();
|
||||
|
||||
LevelRange levelRange;
|
||||
QList<QBarSet*> barSets;
|
||||
|
||||
// Create bar sets
|
||||
if (ui->groupBox_Species->isChecked()) {
|
||||
// Species box is active, we just display data for the selected species.
|
||||
const QString species = ui->comboBox_Species->currentText();
|
||||
barSets.append(createLevelDistributionBarSet(species, groupName, true));
|
||||
levelRange = getLevelRange(species, groupName);
|
||||
} else {
|
||||
// Species box is inactive, we display data for all species in the table.
|
||||
for (const auto species : this->speciesInLegendOrder)
|
||||
barSets.append(createLevelDistributionBarSet(species, groupName, false));
|
||||
levelRange = this->groupedLevelRanges.value(groupName);
|
||||
}
|
||||
|
||||
// Set up series
|
||||
auto series = new QStackedBarSeries();
|
||||
//series->setLabelsVisible();
|
||||
series->append(barSets);
|
||||
|
||||
// Set up chart
|
||||
auto chart = new QChart();
|
||||
chart->addSeries(series);
|
||||
chart->setTheme(currentTheme());
|
||||
chart->setAnimationOptions(QChart::SeriesAnimations);
|
||||
chart->legend()->setVisible(true);
|
||||
chart->legend()->setShowToolTips(true);
|
||||
chart->legend()->setAlignment(Qt::AlignBottom);
|
||||
applySpeciesColors(barSets); // Has to happen after theme is set
|
||||
|
||||
// X-axis is the level range.
|
||||
QBarCategoryAxis *axisX = new QBarCategoryAxis();
|
||||
for (int i = levelRange.min; i <= levelRange.max; i++)
|
||||
axisX->append(QString::number(i));
|
||||
chart->addAxis(axisX, Qt::AlignBottom);
|
||||
series->attachAxis(axisX);
|
||||
|
||||
// Y-axis is the % frequency
|
||||
QValueAxis *axisY = new QValueAxis();
|
||||
axisY->setLabelFormat("%u%%");
|
||||
chart->addAxis(axisY, Qt::AlignLeft);
|
||||
series->attachAxis(axisY);
|
||||
|
||||
// We round the y-axis max up to a multiple of 5.
|
||||
auto roundUp = [](int num, int multiple) {
|
||||
auto remainder = num % multiple;
|
||||
if (remainder == 0)
|
||||
return num;
|
||||
return num + multiple - remainder;
|
||||
};
|
||||
axisY->setMax(roundUp(qCeil(axisY->max()), 5));
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
QChart::ChartTheme WildMonChart::currentTheme() const {
|
||||
return static_cast<QChart::ChartTheme>(ui->comboBox_Theme->currentData().toInt());
|
||||
}
|
||||
|
||||
void WildMonChart::updateTheme() {
|
||||
auto theme = currentTheme();
|
||||
porymapConfig.wildMonChartTheme = ui->comboBox_Theme->currentText();
|
||||
|
||||
// In order to keep the color of each species in the legend consistent across
|
||||
// charts we save species->color mappings. The legend colors are overwritten
|
||||
// when we change themes, so we need to recalculate them. We let the species
|
||||
// distribution chart determine what those mapping are (it always includes every
|
||||
// species in the table) and then we apply those mappings to subsequent charts.
|
||||
QChart *chart = ui->chartView_SpeciesDistribution->chart();
|
||||
if (!chart)
|
||||
return;
|
||||
chart->setTheme(theme);
|
||||
saveSpeciesColors(static_cast<QAbstractBarSeries*>(chart->series().at(0))->barSets());
|
||||
|
||||
chart = ui->chartView_LevelDistribution->chart();
|
||||
if (chart) {
|
||||
chart->setTheme(theme);
|
||||
applySpeciesColors(static_cast<QAbstractBarSeries*>(chart->series().at(0))->barSets());
|
||||
}
|
||||
}
|
||||
|
||||
void WildMonChart::saveSpeciesColors(const QList<QBarSet*> &barSets) {
|
||||
this->speciesToColor.clear();
|
||||
for (auto set : barSets)
|
||||
this->speciesToColor.insert(set->label(), set->color());
|
||||
}
|
||||
|
||||
void WildMonChart::applySpeciesColors(const QList<QBarSet*> &barSets) {
|
||||
for (auto set : barSets)
|
||||
set->setColor(this->speciesToColor.value(set->label()));
|
||||
}
|
||||
|
||||
// Turn off the animation once it's played, otherwise it replays any time the window changes size.
|
||||
void WildMonChart::limitChartAnimation(QChart *chart) {
|
||||
// Chart may be destroyed before the animation finishes
|
||||
QPointer<QChart> safeChart = chart;
|
||||
|
||||
// QChart has no signal for when the animation is finished, so we use a timer to stop the animation.
|
||||
// It is technically possible to get the chart to freeze mid-animation by resizing the window after
|
||||
// the timer starts but before it finishes, but 1. animations are short so this is difficult to do,
|
||||
// and 2. the issue resolves if the window is resized afterwards, so it's probably fine.
|
||||
QTimer::singleShot(chart->animationDuration() + 500, [safeChart] {
|
||||
if (safeChart) safeChart->setAnimationOptions(QChart::NoAnimation);
|
||||
});
|
||||
}
|
||||
|
||||
void WildMonChart::showHelpDialog() {
|
||||
static const QString text = "This window provides some visualizations of the data in your current Wild Pokémon tab";
|
||||
static const QString informative =
|
||||
"The <b>Species Distribution</b> tab shows the cumulative encounter chance for each species "
|
||||
"in the table. In other words, it answers the question \"What is the likelihood of encountering "
|
||||
"each species in a single encounter?\""
|
||||
"<br><br>"
|
||||
"The <b>Level Distribution</b> tab shows the chance of encountering each species at a particular level. "
|
||||
"In the top left under <b>Group</b> you can select which encounter group to show data for. "
|
||||
"In the top right under <b>Species</b> you can select which species to show data for. "
|
||||
"<br><br>"
|
||||
"<b>Individual Mode</b> on the <b>Level Distribution</b> tab toggles whether data is shown for all species in the table. "
|
||||
"The percentages will update to reflect whether you're showing all species or just that individual species. "
|
||||
"In other words, while <b>Individual Mode</b> is checked the chart is answering the question \"If a species x "
|
||||
"is encountered, what is the likelihood that it will be level y\", and while <b>Individual Mode</b> is not checked, "
|
||||
"it answers the question \"For a single encounter, what is the likelihood of encountering a species x at level y.\"";
|
||||
QMessageBox msgBox(QMessageBox::Information, "porymap", text, QMessageBox::Close, this);
|
||||
msgBox.setTextFormat(Qt::RichText);
|
||||
msgBox.setInformativeText(informative);
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
void WildMonChart::closeEvent(QCloseEvent *event) {
|
||||
porymapConfig.wildMonChartGeometry = saveGeometry();
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
#endif // __has_include(<QtCharts>)
|
Loading…
Reference in a new issue