Merge branch 'master' into label-copy
|
@ -7,7 +7,11 @@ 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. If porymap is used on a project that is not up-to-date with the breaking changes, then porymap will likely break or behave improperly.
|
||||
|
||||
## [Unreleased]
|
||||
### Breaking Changes
|
||||
- Proper support for pokefirered's clone objects was added, which requires the changes made in [pokefirered/#484](https://github.com/pret/pokefirered/pull/484).
|
||||
|
||||
### Added
|
||||
- Add Copy/Paste for metatiles in the Tileset Editor.
|
||||
- Add ability to set the opacity of the scripting overlay.
|
||||
- Add ability to get/set map header properties and read tile pixel data via the API.
|
||||
- Add button to copy the full metatile label to the clipboard in the Tileset Editor.
|
||||
|
@ -16,12 +20,15 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
|
|||
- If an object event is inanimate, it will always render using its first frame.
|
||||
- Only log "Unknown custom script function" when a registered script function is not present in any script.
|
||||
- Unused metatile attribute bits that are set are preserved instead of being cleared.
|
||||
- The wild encounter editor is automatically disabled if the encounter JSON data cannot be read
|
||||
- Overhauled the region map editor, adding support for tilemaps, and significant customization. Also now supports pokefirered.
|
||||
|
||||
### Fixed
|
||||
- Fix cursor tile outline not updating at the end of a dragged selection.
|
||||
- Fix cursor tile and player view outlines exiting map bounds while painting.
|
||||
- Fix cursor tile and player view outlines not updating immediately when toggled in Collision view.
|
||||
- Fix selected space not updating while painting in Collision view.
|
||||
- Fix the map music dropdown being empty when importing a map from Advance Map.
|
||||
|
||||
## [4.5.0] - 2021-12-26
|
||||
### Added
|
||||
|
|
|
@ -60,7 +60,7 @@ Object events are typically used for NPCs (non-player-characters). More technic
|
|||
Object Event Properties
|
||||
|
||||
Id
|
||||
This is the local id of the object in the map. Some script values use this local id to specify object when using scripting commands such as `applymovement`.
|
||||
This is the local id of the object in the map. Some script values use this local id to specify an object when using scripting commands such as `applymovement`.
|
||||
|
||||
Sprite
|
||||
The sprite that is used by the object.
|
||||
|
@ -83,8 +83,27 @@ Trainer Type
|
|||
Sight Radius or Berry Tree ID
|
||||
If the object is a trainer, this property control how many tiles the trainer can see to spot the player for battle. If the object is a berry tree, this specifies the global id of the berry tree. Each berry tree in the game has a unique berry tree id.
|
||||
|
||||
In Connection
|
||||
Exclusive to pokefirered. Used to replace objects that are visible in a map's connection with their corresponding object on the connecting map. When checked, these objects will make odd use of other fields; its trainer type value will be the connecting map number, its Sight Radius / Berry Tree Id will be the connecting map group, and its z coordinate will be the object's local id on the connecting map.
|
||||
Clone Object Events
|
||||
-------------------
|
||||
|
||||
Clone Object events are a special type of object that inherits its properties from another Object event. They are used in-game to load objects that are visible in the connecting area of adjacent maps. The targeted object to clone is specified by id and map name. If the targeted object does not exist, or it's also a clone, the sprite for graphics id 0 will be displayed instead. Double-clicking on a Clone Object will open the targeted map with the targeted object selected. This event type is exclusive to pokefirered projects; the code to process them does not exist in pokeemerald/pokeruby.
|
||||
|
||||
.. figure:: images/editing-map-events/event-clone-object.png
|
||||
:alt: Clone Object Event Properties
|
||||
|
||||
Clone Object Event Properties
|
||||
|
||||
Id
|
||||
This is the local id of the object in the map. Some script values use this local id to specify an object when using scripting commands such as `applymovement`.
|
||||
|
||||
Sprite
|
||||
The sprite that is used by the object. Clone Objects inherit their sprite from the targeted object, so this cannot be edited. This field is not actually read by the game.
|
||||
|
||||
Target Local Id
|
||||
The local id of the object to be cloned.
|
||||
|
||||
Target Map
|
||||
The name of the map the object to be cloned is on.
|
||||
|
||||
.. _event-warps:
|
||||
|
||||
|
|
BIN
docsrc/manual/images/editing-map-events/event-clone-object.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
docsrc/manual/images/region-map-editor/new-configure-window.png
Normal file
After Width: | Height: | Size: 483 KiB |
BIN
docsrc/manual/images/region-map-editor/rme-config-properties.png
Normal file
After Width: | Height: | Size: 384 KiB |
BIN
docsrc/manual/images/region-map-editor/rme-main-window.png
Normal file
After Width: | Height: | Size: 378 KiB |
BIN
docsrc/manual/images/region-map-editor/rme-new-entries-tab.png
Normal file
After Width: | Height: | Size: 384 KiB |
BIN
docsrc/manual/images/region-map-editor/rme-new-layout-tab.png
Normal file
After Width: | Height: | Size: 378 KiB |
|
@ -2,24 +2,73 @@
|
|||
The Region Map Editor
|
||||
*********************
|
||||
|
||||
This is where you edit the region map for your game. To open the region map
|
||||
editor, navigate to *Tools -> Region Map Editor* from porymap's main window.
|
||||
This is where you edit the region maps for your game. You are able to edit the
|
||||
background tilemap, the layout of map sections, and the array of map section entries
|
||||
which determines the dimensions of each section.
|
||||
|
||||
.. note::
|
||||
The region map editor is currently only available for pokeemerald and pokeruby.
|
||||
To open the region map editor, navigate to *Tools -> Region Map Editor* from
|
||||
porymap's main window. There is also a keyboard shortcut which is by default ``Ctrl+M``.
|
||||
|
||||
When you first open the region map editor, your window will look like this:
|
||||
When you first open the region map editor, you will need to configure porymap to
|
||||
read your region map data. There are defaults for every base game project available
|
||||
which should be sufficient for most users.
|
||||
|
||||
.. figure:: images/region-map-editor/rme-new-window.png
|
||||
:scale: 75%
|
||||
.. figure:: images/region-map-editor/new-configure-window.png
|
||||
:align: center
|
||||
:width: 75%
|
||||
:alt: RME Window
|
||||
|
||||
Region Maps Configurator
|
||||
|
||||
Porymap supports multiple region maps for any project.
|
||||
By default, pokeemerald and pokefirered use this feature.
|
||||
For a more custom region map, you can use the *Add Region Map...* button to
|
||||
create a new region map configuration from scratch. You can also double-click on any existing
|
||||
region map in the list to bring this window up to make changes.
|
||||
|
||||
.. figure:: images/region-map-editor/rme-config-properties.png
|
||||
:align: center
|
||||
:width: 50%
|
||||
:alt: RME Config Prop
|
||||
|
||||
Region Map Properties Window
|
||||
|
||||
This window has many options for users to define:
|
||||
|
||||
.. csv-table::
|
||||
:header: Field,Explanation,Restrictions
|
||||
:widths: 10, 30, 20
|
||||
|
||||
alias,something for porymap to distinguish between your maps,unique & valid json string
|
||||
**Tilemap Properties**,,
|
||||
format,format of the tiles,Plain *or* 4bpp *or* 8bpp
|
||||
width,width *in tiles* of the tilemap,16 *or* 32 *or* 64 *or* 128
|
||||
height,height *in tiles* of the tilemap,valid corresponding height based on width
|
||||
tileset path,the relative path to the tile image from project root,valid filepath string
|
||||
tilemap path,the relative path to the tilemap binary from project root,valid filepath string
|
||||
palette path,*optional* relative path to ``.pal`` file from project root,valid filepath string
|
||||
**Layout Properties**,*can be unchecked for maps without layouts*,
|
||||
format,the format to read the layout file,C array *or* binary
|
||||
layout path,the relative path from project root to layout file,valid filepath string
|
||||
width,the width of the layout,non-negative integer
|
||||
left offset,the position on the tilemap which defines layout x=0,width + left offset < tilemap width
|
||||
height,the height of the layout,non-negative integer
|
||||
top offset,the position on the tilemap which defines layout y=0,height + top offset < tilemap height
|
||||
|
||||
When you are finished configuring your region maps, you can select *OK*. This will
|
||||
display the main editor window.
|
||||
|
||||
.. figure:: images/region-map-editor/rme-main-window.png
|
||||
:align: center
|
||||
:width: 75%
|
||||
:alt: RME Config Prop
|
||||
|
||||
Region Map Editor Window
|
||||
|
||||
This window is split vertically--the region map editing is done at the top,
|
||||
while the zoomed-in city maps are edited at the bottom. You can use the
|
||||
sliders to zoom in and out on each of the view panes. You will notice
|
||||
This window has a combobox labeled "Region" which you can use to select the current
|
||||
region map you want to edit.
|
||||
|
||||
You will notice
|
||||
that there are three different tabs above the image of the region map
|
||||
(:ref:`Background Image <background-image-tab>`,
|
||||
:ref:`Map Layout <map-layout-tab>`,
|
||||
|
@ -39,24 +88,13 @@ are unhappy with what you have done, you can undo (``Ctrl+Z`` or *Edit -> Undo*)
|
|||
and redo (``Ctrl+Y`` or *Edit -> Redo*) your changes. Right-clicking on the map
|
||||
image will select the tile under your mouse from the tile selector.
|
||||
|
||||
If your tilemap format is not "Plain", then you can also select the palette,
|
||||
h-flip, and v-flip of any tile you are painting with.
|
||||
|
||||
If you want to clear the background image, *Edit -> Clear Background Image*
|
||||
will set all tiles to the first tile in the tile selector.
|
||||
|
||||
.. figure:: images/region-map-editor/rme-painting-image.gif
|
||||
:scale: 75%
|
||||
:align: center
|
||||
:alt: RME Paint
|
||||
|
||||
Drawing on the Region Map Image
|
||||
|
||||
It is likely that you will want to use your own tiles for your region map. You
|
||||
can import a tile image by navigating to *Tools -> Import Region Map Image Tiles*.
|
||||
There are strict requirements for your region map tile image. It must (1) be
|
||||
indexed with a 256 color palette\*, (2) be composed of 8x8 pixel tiles, (3) have 256
|
||||
or fewer tiles.
|
||||
|
||||
\* While the region map tile image requires a 256-color palette, the image only
|
||||
uses the 32 colors beginning at index 112 in the palette.
|
||||
You can use the sliders to zoom in and out on each of the view panes.
|
||||
|
||||
.. _map-layout-tab:
|
||||
|
||||
|
@ -67,9 +105,9 @@ The layout tab is where map sections are placed on the region map. When the
|
|||
player looks at the region map in-game, the layout determines the map under the
|
||||
cursor.
|
||||
|
||||
.. figure:: images/region-map-editor/rme-layout-tab.png
|
||||
:scale: 75%
|
||||
.. figure:: images/region-map-editor/rme-new-layout-tab.png
|
||||
:align: center
|
||||
:width: 75%
|
||||
:alt: RME Layout
|
||||
|
||||
RME Layout Tab
|
||||
|
@ -78,29 +116,15 @@ To modify the region map layout, select a position by clicking on the map image
|
|||
and higlighting a single square. The "Map Section" combobox will be populated
|
||||
with all of the map sections defined in ``include/constants/region_map_sections.h``.
|
||||
Select the map section you want to associate with the selected position on the
|
||||
region map. To change the popup name of the map section when you enter the map,
|
||||
type it into the "Map Name" box. The popup name is tied to the map section, so
|
||||
each layout square with the same map section will share a name.
|
||||
region map.
|
||||
|
||||
If you want to start from a blank layout, *Edit -> Clear Map Layout* will set
|
||||
all layout squares to the value of ``MAPSEC_NONE``.
|
||||
There are a couple of tools which make editing multiple layout squares simultaneously easier.
|
||||
|
||||
When adding new region map sections, the layout will be affected. This is
|
||||
because the layout is stored as a binary file and uses the raw value of each
|
||||
map section. In order to fix your layout to account for this, you can swap two
|
||||
values for the entire layout with *Edit -> Swap*.
|
||||
*Edit -> Clear Map Layout* will set all squares in the layout to ``MAPSEC_NONE``.
|
||||
|
||||
In this example, ``MAPSEC_NEW_MAPSEC`` is inserted before ``MAPSEC_NONE``, and
|
||||
therefore the layout will link the original value of ``MAPSEC_NONE`` to the new
|
||||
map section ``MAPSEC_NEW_MAPSEC``. Instances of ``MAPSEC_NEW_MAPSEC`` are swapped
|
||||
with ``MAPSEC_NONE``.
|
||||
*Edit -> Swap Layout Sections...* will exchange two layout sections with each other.
|
||||
|
||||
.. figure:: images/region-map-editor/rme-layout-swap.gif
|
||||
:scale: 75%
|
||||
:align: center
|
||||
:alt: RME Swap
|
||||
|
||||
Swapping Map Sections
|
||||
*Edit -> Replace Layout Section...* will replace all instances of one section with another.
|
||||
|
||||
The "Delete Square" button simply resets a single layout square to ``MAPSEC_NONE``.
|
||||
|
||||
|
@ -111,10 +135,10 @@ Map Entries Tab
|
|||
|
||||
A region map entry is the area on the region map that spans an entire map section.
|
||||
This determines, for example, where the player's head appears on the region map
|
||||
in-game. Entries are stored at ``src/data/region_map/region_map_entries.h``.
|
||||
in-game. Entries are stored in ``src/data/region_map/region_map_sections.json``.
|
||||
|
||||
.. figure:: images/region-map-editor/rme-entries-tab.png
|
||||
:scale: 75%
|
||||
.. figure:: images/region-map-editor/rme-new-entries-tab.png
|
||||
:width: 75%
|
||||
:align: center
|
||||
:alt: RME Entries
|
||||
|
||||
|
@ -126,29 +150,8 @@ You can also drag the entry around the map. The "x" and "y" values correspond t
|
|||
the position of the entry's top-left square on the region map. The "Dimensions"
|
||||
"width" and "height" spinboxes will change the size of the map entry.
|
||||
|
||||
City Maps
|
||||
---------
|
||||
|
||||
In the bottom half of the region map editor window, city maps can be edited.
|
||||
You paint on this the same way you paint on the region map background image.
|
||||
|
||||
.. figure:: images/region-map-editor/rme-painting-city.gif
|
||||
:scale: 60%
|
||||
:align: center
|
||||
:alt: City Paint
|
||||
|
||||
Drawing on the City Map
|
||||
|
||||
To use custom tiles, there is a tile image importer under
|
||||
*Tools -> Import City Map Image Tiles*. These images must (1) be indexed with a
|
||||
16 color palette, (2) be made up of 8x8 pixel tiles, (3) have 256 or fewer tiles.
|
||||
|
||||
You can add a new city map by pressing the |new-city-map-button| button.
|
||||
|
||||
.. |new-city-map-button|
|
||||
image:: images/region-map-editor/rme-new-city-map-button.png
|
||||
|
||||
Currently, it is not possible to associate a city map to a region map location,
|
||||
but that functionality will be added in a future update.
|
||||
To change the popup name of the map section when you enter the map, type it
|
||||
into the "Map Name" box.
|
||||
|
||||
|
||||
|
|
|
@ -39,10 +39,10 @@ determined by this file.
|
|||
``use_custom_border_size``, 0, project, yes, Whether to allow variable border sizes
|
||||
``enable_event_weather_trigger``, 1 if not ``pokefirered``, project, yes, Allows adding Weather Trigger events
|
||||
``enable_event_secret_base``, 1 if not ``pokefirered``, project, yes, Allows adding Secret Base events
|
||||
``enable_event_clone_object``, 1 if ``pokefirered``, project, yes, Allows adding Clone Object events
|
||||
``enable_hidden_item_quantity``, 1 if ``pokefirered``, project, yes, Adds ``Quantity`` to Hidden Item events
|
||||
``enable_hidden_item_requires_itemfinder``, 1 if ``pokefirered``, project, yes, Adds ``Requires Itemfinder`` to Hidden Item events
|
||||
``enable_heal_location_respawn_data``, 1 if ``pokefirered``, project, yes, Adds ``Respawn Map`` and ``Respawn NPC`` to Heal Location events
|
||||
``enable_object_event_in_connection``, 1 if ``pokefirered``, project, yes, Adds ``In Connection`` to Object events
|
||||
``enable_floor_number``, 1 if ``pokefirered``, project, yes, Adds ``Floor Number`` to map headers
|
||||
``create_map_text_file``, 1 if not ``pokeemerald``, project, yes, A ``text.inc`` or ``text.pory`` file will be created for any new map
|
||||
``enable_triple_layer_metatiles``, 0, project, yes, Enables triple-layer metatiles (See https://github.com/pret/pokeemerald/wiki/Triple-layer-metatiles)
|
||||
|
|
706
forms/regionmappropertiesdialog.ui
Normal file
|
@ -0,0 +1,706 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RegionMapPropertiesDialog</class>
|
||||
<widget class="QDialog" name="RegionMapPropertiesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>564</width>
|
||||
<height>902</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Region Map Properties</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>alias</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="config_alias">
|
||||
<property name="toolTip">
|
||||
<string>A nickname for this region map that will differentiate it from others (should be unique).</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="message_alias">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Tilemap Properties</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>format</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="config_tilemapFormat">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The tilemap format can be either:</p><p>1) Plain (tilemap is a list of 8-bit tile indexes into the tileset)</p><p>2) 4BPP (tilemap entries are 16 bits, with x/y-flip, and palette index for 16 16-color palettes)</p><p>3) 8BPP (tilemap entries are 16 bits, with x/y-flip, single 256-color palette)</p></body></html></string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>plain</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4bpp</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>8bpp</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="message_tilemapFormat">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="message_tilemapWidth">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="config_tilemapHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>75</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The height of the tilemap</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>tileset path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<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="QLineEdit" name="config_tilemapImagePath">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>350</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Path to the tileset image (.png) relative to the project root.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browse_tilesetImagePath">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="message_tilemapImagePath">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>tilemap path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Path to the tilemap binary relative to the project root.</p></body></html></string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</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>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="config_tilemapBinPath"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browse_tilemapBinPath">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLabel" name="message_tilemapBinPath">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>palette path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</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="QLineEdit" name="config_tilemapPalettePath">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>(optional) Path to the .pal JASC palette file</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browse_tilemapPalettePath">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="message_tilemapHeight">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="config_tilemapWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>75</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The width of the tilemap</p></body></html></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="group_layout">
|
||||
<property name="title">
|
||||
<string>Layout Properties</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>format</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="config_layoutFormat">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The format of the layout file, can be a C array in a text file with &quot;MAPSEC_&quot;-prefixed constants, or a binary file where each byte is a value of some &quot;MAPSEC_&quot;-prefixed constant.</p></body></html></string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>C array</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>binary</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="message_layoutFormat">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>layout path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QFrame" name="frame_5">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<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="QLineEdit" name="config_layoutPath">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The path to the layout file, relative to the project root.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browse_layoutPath">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="message_layoutPath">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<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="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="config_layoutWidth">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>75</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The layout width.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<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="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>left offset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="config_leftOffs">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The offset from the left of the tilemap where the layout starts.</p><p>(ie, coordinate (0,0) in the layout would be (offset left, offset top) in the tilemap).</p></body></html></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>85</width>
|
||||
<height>2</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="message_layoutWidth">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<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="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>height</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="config_layoutHeight">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>75</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The layout height.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>255</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>87</width>
|
||||
<height>13</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>top offset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="config_topOffs">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The offset from the top of the tilemap where the layout starts.</p><p>(ie, coordinate (0,0) in the layout would be (offset left, offset top) in the tilemap).</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>87</width>
|
||||
<height>13</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="message_layoutHeight">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #ff5c33</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<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 row="9" column="1">
|
||||
<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>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>RegionMapPropertiesDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>RegionMapPropertiesDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -567,6 +567,8 @@
|
|||
<property name="title">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
<addaction name="actionCopy"/>
|
||||
<addaction name="actionPaste"/>
|
||||
<addaction name="actionUndo"/>
|
||||
<addaction name="actionRedo"/>
|
||||
</widget>
|
||||
|
@ -663,6 +665,22 @@
|
|||
<string>Import Secondary Metatiles from Advance Map 1.92...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopy">
|
||||
<property name="text">
|
||||
<string>Copy</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+C</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPaste">
|
||||
<property name="text">
|
||||
<string>Paste</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+V</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
@ -148,7 +148,7 @@ public:
|
|||
this->enableHiddenItemQuantity = false;
|
||||
this->enableHiddenItemRequiresItemfinder = false;
|
||||
this->enableHealLocationRespawnData = false;
|
||||
this->enableObjectEventInConnection = false;
|
||||
this->enableEventCloneObject = false;
|
||||
this->enableFloorNumber = false;
|
||||
this->createMapTextFile = false;
|
||||
this->enableTripleLayerMetatiles = false;
|
||||
|
@ -178,8 +178,8 @@ public:
|
|||
bool getHiddenItemRequiresItemfinderEnabled();
|
||||
void setHealLocationRespawnDataEnabled(bool enable);
|
||||
bool getHealLocationRespawnDataEnabled();
|
||||
void setObjectEventInConnectionEnabled(bool enable);
|
||||
bool getObjectEventInConnectionEnabled();
|
||||
void setEventCloneObjectEnabled(bool enable);
|
||||
bool getEventCloneObjectEnabled();
|
||||
void setFloorNumberEnabled(bool enable);
|
||||
bool getFloorNumberEnabled();
|
||||
void setCreateMapTextFileEnabled(bool enable);
|
||||
|
@ -206,7 +206,7 @@ private:
|
|||
bool enableHiddenItemQuantity;
|
||||
bool enableHiddenItemRequiresItemfinder;
|
||||
bool enableHealLocationRespawnData;
|
||||
bool enableObjectEventInConnection;
|
||||
bool enableEventCloneObject;
|
||||
bool enableFloorNumber;
|
||||
bool createMapTextFile;
|
||||
bool enableTripleLayerMetatiles;
|
||||
|
|
|
@ -14,6 +14,7 @@ class EventType
|
|||
{
|
||||
public:
|
||||
static QString Object;
|
||||
static QString CloneObject;
|
||||
static QString Warp;
|
||||
static QString Trigger;
|
||||
static QString WeatherTrigger;
|
||||
|
@ -23,6 +24,16 @@ public:
|
|||
static QString HealLocation;
|
||||
};
|
||||
|
||||
class EventGroup
|
||||
{
|
||||
public:
|
||||
static QString Object;
|
||||
static QString Warp;
|
||||
static QString Coord;
|
||||
static QString Bg;
|
||||
static QString Heal;
|
||||
};
|
||||
|
||||
class DraggablePixmapItem;
|
||||
class Project;
|
||||
class Event
|
||||
|
@ -68,6 +79,7 @@ public:
|
|||
|
||||
static Event* createNewEvent(QString, QString, Project*);
|
||||
static Event* createNewObjectEvent(Project*);
|
||||
static Event* createNewCloneObjectEvent(Project*, QString);
|
||||
static Event* createNewWarpEvent(QString);
|
||||
static Event* createNewHealLocationEvent(QString);
|
||||
static Event* createNewTriggerEvent(Project*);
|
||||
|
@ -75,8 +87,12 @@ public:
|
|||
static Event* createNewSignEvent(Project*);
|
||||
static Event* createNewHiddenItemEvent(Project*);
|
||||
static Event* createNewSecretBaseEvent(Project*);
|
||||
static bool isValidType(QString event_type);
|
||||
static QString typeToGroup(QString event_type);
|
||||
static int getIndexOffset(QString group_type);
|
||||
|
||||
OrderedJson::object buildObjectEventJSON();
|
||||
OrderedJson::object buildCloneObjectEventJSON(const QMap<QString, QString> &);
|
||||
OrderedJson::object buildWarpEventJSON(const QMap<QString, QString> &);
|
||||
OrderedJson::object buildTriggerEventJSON();
|
||||
OrderedJson::object buildWeatherTriggerEventJSON();
|
||||
|
@ -86,7 +102,7 @@ public:
|
|||
void setPixmapFromSpritesheet(QImage, int, int, bool);
|
||||
int getPixelX();
|
||||
int getPixelY();
|
||||
QMap<QString, bool> getExpectedFields();
|
||||
QSet<QString> getExpectedFields();
|
||||
void readCustomValues(QJsonObject values);
|
||||
void addCustomValuesTo(OrderedJson::object *obj);
|
||||
void setFrameFromMovement(QString);
|
||||
|
|
|
@ -54,4 +54,18 @@ public:
|
|||
static int getAttributesSize(BaseGameVersion version);
|
||||
};
|
||||
|
||||
inline bool operator==(const Metatile &a, const Metatile &b) {
|
||||
return a.behavior == b.behavior &&
|
||||
a.layerType == b.layerType &&
|
||||
a.encounterType == b.encounterType &&
|
||||
a.terrainType == b.terrainType &&
|
||||
a.unusedAttributes == b.unusedAttributes &&
|
||||
a.label == b.label &&
|
||||
a.tiles == b.tiles;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Metatile &a, const Metatile &b) {
|
||||
return !(operator==(a, b));
|
||||
}
|
||||
|
||||
#endif // METATILE_H
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#define REGIONMAP_H
|
||||
|
||||
#include "map.h"
|
||||
#include "project.h"
|
||||
#include "tilemaptileselector.h"
|
||||
#include "history.h"
|
||||
|
||||
|
@ -15,138 +14,183 @@
|
|||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
|
||||
enum RegionMapEditorBox {
|
||||
BackgroundImage = 1,
|
||||
CityMapImage = 2,
|
||||
};
|
||||
#include <memory>
|
||||
using std::shared_ptr;
|
||||
|
||||
class RegionMapHistoryItem {
|
||||
public:
|
||||
int which;
|
||||
int mapWidth = 0;
|
||||
int mapHeight = 0;
|
||||
QVector<uint8_t> tiles;
|
||||
QString cityMap;
|
||||
RegionMapHistoryItem(int which, QVector<uint8_t> tiles, QString cityMap) {
|
||||
this->which = which;
|
||||
this->tiles = tiles;
|
||||
this->cityMap = cityMap;
|
||||
}
|
||||
RegionMapHistoryItem(int which, QVector<uint8_t> tiles, int width, int height) {
|
||||
this->which = which;
|
||||
this->tiles = tiles;
|
||||
this->mapWidth = width;
|
||||
this->mapHeight = height;
|
||||
}
|
||||
~RegionMapHistoryItem() {}
|
||||
};
|
||||
class Project;
|
||||
|
||||
class RegionMapEntry
|
||||
struct LayoutSquare
|
||||
{
|
||||
public:
|
||||
RegionMapEntry()=default;
|
||||
RegionMapEntry(int x_, int y_, int width_, int height_, QString name_) {
|
||||
this-> x = x_;
|
||||
this-> y = y_;
|
||||
this-> width = width_;
|
||||
this-> height = height_;
|
||||
this-> name = name_;
|
||||
}
|
||||
LayoutSquare() : map_section("MAPSEC_NONE"), x(-1), y(-1), has_map(false) {}
|
||||
QString map_section;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
QString name;
|
||||
|
||||
void setX(int);
|
||||
void setY(int);
|
||||
void setWidth(int);
|
||||
void setHeight(int);
|
||||
bool has_map;
|
||||
};
|
||||
|
||||
class RegionMapSquare
|
||||
struct MapSectionEntry
|
||||
{
|
||||
public:
|
||||
int x = -1;
|
||||
int y = -1;
|
||||
uint8_t tile_img_id = 0x00;
|
||||
uint8_t secid = 0x00;
|
||||
bool has_map = false;
|
||||
bool has_city_map = false;
|
||||
bool duplicated = false;
|
||||
QString map_name;
|
||||
QString mapsec;
|
||||
QString city_map_name;
|
||||
QString name = "";
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 1;
|
||||
int height = 1;
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
class RegionMap
|
||||
class RegionMap : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
RegionMap() = default;
|
||||
RegionMap() = delete;
|
||||
RegionMap(Project *);
|
||||
|
||||
~RegionMap() {}
|
||||
|
||||
Project *project = nullptr;
|
||||
|
||||
QVector<RegionMapSquare> map_squares;
|
||||
History<RegionMapHistoryItem*> history;
|
||||
bool loadMapData(poryjson::Json);
|
||||
bool loadTilemap(poryjson::Json);
|
||||
bool loadLayout(poryjson::Json);
|
||||
bool loadEntries();
|
||||
|
||||
QMap<QString, QString> sMapNamesMap;
|
||||
QMap<QString, RegionMapEntry> mapSecToMapEntry;
|
||||
QVector<QString> sMapNames;
|
||||
|
||||
const int padLeft = 1;
|
||||
const int padRight = 3;
|
||||
const int padTop = 2;
|
||||
const int padBottom = 3;
|
||||
|
||||
bool init(Project*);
|
||||
|
||||
bool readBkgImgBin();
|
||||
bool readLayout();
|
||||
void setEntries(tsl::ordered_map<QString, MapSectionEntry> *entries) { this->region_map_entries = entries; }
|
||||
void setEntries(tsl::ordered_map<QString, MapSectionEntry> entries) { *(this->region_map_entries) = entries; }
|
||||
void clearEntries() { this->region_map_entries->clear(); }
|
||||
MapSectionEntry getEntry(QString section);
|
||||
void setEntry(QString section, MapSectionEntry entry);
|
||||
void removeEntry(QString section);
|
||||
|
||||
void save();
|
||||
void saveTileImages();
|
||||
void saveBkgImgBin();
|
||||
void saveTilemap();
|
||||
void saveLayout();
|
||||
void saveOptions(int id, QString sec, QString name, int x, int y);
|
||||
|
||||
void resize(int width, int height);
|
||||
void resizeTilemap(int width, int height, bool update = true);
|
||||
void resetSquare(int index);
|
||||
void clearLayout();
|
||||
void clearImage();
|
||||
void replaceSectionId(unsigned oldId, unsigned newId);
|
||||
void replaceSection(QString oldSection, QString newSection);
|
||||
void swapSections(QString secA, QString secB);
|
||||
|
||||
int width();
|
||||
int height();
|
||||
QSize imgSize();
|
||||
unsigned getTileId(int index);
|
||||
shared_ptr<TilemapTile> getTile(int index);
|
||||
unsigned getTileId(int x, int y);
|
||||
int getMapSquareIndex(int x, int y);
|
||||
QString pngPath();
|
||||
void setTemporaryPngPath(QString);
|
||||
QString cityTilesPath();
|
||||
void setTemporaryCityTilesPath(QString);
|
||||
shared_ptr<TilemapTile> getTile(int x, int y);
|
||||
bool squareHasMap(int index);
|
||||
QString squareMapSection(int index);
|
||||
void setSquareMapSection(int index, QString section);
|
||||
int squareX(int index);
|
||||
int squareY(int index);
|
||||
bool squareInLayout(int x, int y);
|
||||
int firstLayoutIndex() { return this->offset_left + this->offset_top * this->tilemap_width; }
|
||||
|
||||
QVector<uint8_t> getTiles();
|
||||
void setTiles(QVector<uint8_t> tileIds);
|
||||
void setTileId(int index, unsigned id);
|
||||
void setTile(int index, TilemapTile &tile);
|
||||
void setTileData(int index, unsigned id, bool hFlip, bool vFlip, int palette);
|
||||
int getMapSquareIndex(int x, int y);
|
||||
|
||||
QString getAlias() { return this->alias; }
|
||||
poryjson::Json::object config();
|
||||
|
||||
QString palPath();
|
||||
QString pngPath();
|
||||
QString entriesPath() { return this->entries_path; }
|
||||
|
||||
QByteArray getTilemap();
|
||||
void setTilemap(QByteArray newTilemap);
|
||||
|
||||
QList<LayoutSquare> getLayout(QString layer);
|
||||
void setLayout(QString layer, QList<LayoutSquare> layout);
|
||||
|
||||
bool layoutEnabled() { return this->layout_format != LayoutFormat::None; }
|
||||
|
||||
QMap<QString, QList<LayoutSquare>> getAllLayouts();
|
||||
void setAllLayouts(QMap<QString, QList<LayoutSquare>> newLayouts);
|
||||
|
||||
QStringList getLayers() { return this->layout_layers; }
|
||||
void setLayer(QString layer) { this->current_layer = layer; }
|
||||
QString getLayer() { return this->current_layer; }
|
||||
|
||||
QString fixCase(QString);
|
||||
|
||||
int padLeft() { return this->offset_left; }
|
||||
int padTop() { return this->offset_top; }
|
||||
int padRight() { return this->tilemap_width - this->layout_width - this->offset_left; }
|
||||
int padBottom() { return this->tilemap_height - this->layout_height - this->offset_top; }
|
||||
|
||||
int tilemapWidth() { return this->tilemap_width; }
|
||||
int tilemapHeight() { return this->tilemap_height; }
|
||||
int tilemapSize() { return this->tilemap_width * this->tilemap_height; }
|
||||
int tilemapBytes();
|
||||
|
||||
int layoutWidth() { return this->layout_width; }
|
||||
int layoutHeight() { return this->layout_height; }
|
||||
void setLayoutDimensions(int width, int height, bool update = true);
|
||||
|
||||
int tilemapToLayoutIndex(int index);
|
||||
|
||||
TilemapFormat tilemapFormat() { return this->tilemap_format; }
|
||||
|
||||
int pixelWidth() { return this->tilemap_width * 8; }
|
||||
int pixelHeight() { return this->tilemap_height * 8; }
|
||||
|
||||
QString fullPath(QString local);
|
||||
|
||||
void commit(QUndoCommand *command);
|
||||
QUndoStack editHistory;
|
||||
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
void emitDisplay();
|
||||
|
||||
signals:
|
||||
void mapNeedsDisplaying();
|
||||
|
||||
private:
|
||||
int layout_width_;
|
||||
int layout_height_;
|
||||
int img_width_;
|
||||
int img_height_;
|
||||
// TODO: defaults needed?
|
||||
tsl::ordered_map<QString, MapSectionEntry> *region_map_entries = nullptr;
|
||||
|
||||
QString region_map_png_path;
|
||||
QString region_map_bin_path;
|
||||
QString region_map_entries_path;
|
||||
QString region_map_layout_bin_path;
|
||||
QString city_map_tiles_path;
|
||||
QString alias = "";
|
||||
|
||||
bool region_map_png_needs_saving = false;
|
||||
bool city_map_png_needs_saving = false;
|
||||
int tilemap_width;
|
||||
int tilemap_height;
|
||||
|
||||
int img_index_(int x, int y);
|
||||
int layout_index_(int x, int y);
|
||||
int layout_width;
|
||||
int layout_height;
|
||||
|
||||
int offset_left;
|
||||
int offset_top;
|
||||
|
||||
TilemapFormat tilemap_format;
|
||||
|
||||
enum class LayoutFormat { None, Binary, CArray };
|
||||
LayoutFormat layout_format;
|
||||
|
||||
QString tileset_path;
|
||||
QString tilemap_path;
|
||||
QString palette_path = "";
|
||||
|
||||
QString entries_path;
|
||||
QString layout_path;
|
||||
|
||||
QString layout_array_label;
|
||||
bool layout_uses_layers = false;
|
||||
QStringList layout_constants;
|
||||
QString layout_qualifiers;
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QVector<shared_ptr<TilemapTile>> tilemap;
|
||||
#else
|
||||
QList<shared_ptr<TilemapTile>> tilemap;
|
||||
#endif
|
||||
|
||||
QStringList layout_layers;
|
||||
QString current_layer;
|
||||
QMap<QString, QList<LayoutSquare>> layouts;
|
||||
|
||||
int get_tilemap_index(int x, int y);
|
||||
int get_layout_index(int x, int y);
|
||||
};
|
||||
|
||||
#endif // REGIONMAP_H
|
||||
|
|
169
include/core/regionmapeditcommands.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
#pragma once
|
||||
#ifndef REGIONMAPEDITCOMMANDS_H
|
||||
#define REGIONMAPEDITCOMMANDS_H
|
||||
|
||||
#include "regionmap.h"
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include <QList>
|
||||
|
||||
class RegionMap;
|
||||
|
||||
enum RMCommandId {
|
||||
ID_EditTilemap = 0,
|
||||
ID_EditLayout,
|
||||
ID_ResizeLayout,
|
||||
ID_EditEntry,
|
||||
ID_RemoveEntry,
|
||||
ID_AddEntry,
|
||||
ID_ResizeTilemap,
|
||||
ID_ClearEntries,
|
||||
};
|
||||
|
||||
|
||||
/// Implements a command to commit tilemap paint actions
|
||||
class EditTilemap : public QUndoCommand {
|
||||
public:
|
||||
EditTilemap(RegionMap *map, QByteArray oldTilemap, QByteArray newTilemap, unsigned actionId, QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
bool mergeWith(const QUndoCommand *command) override;
|
||||
int id() const override { return RMCommandId::ID_EditTilemap; }
|
||||
|
||||
protected:
|
||||
RegionMap *map;
|
||||
|
||||
QByteArray oldTilemap;
|
||||
QByteArray newTilemap;
|
||||
|
||||
unsigned actionId;
|
||||
};
|
||||
|
||||
|
||||
/// Edit region map section layout
|
||||
class EditLayout : public QUndoCommand {
|
||||
public:
|
||||
EditLayout(RegionMap *map, QString layer, int index, QList<LayoutSquare> oldLayout, QList<LayoutSquare> newLayout, QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
bool mergeWith(const QUndoCommand *command) override;
|
||||
int id() const override { return RMCommandId::ID_EditLayout; }
|
||||
|
||||
private:
|
||||
RegionMap *map;
|
||||
|
||||
int index;
|
||||
QString layer;
|
||||
QList<LayoutSquare> oldLayout;
|
||||
QList<LayoutSquare> newLayout;
|
||||
};
|
||||
|
||||
|
||||
/// Edit Layout Dimensions
|
||||
class ResizeLayout : public QUndoCommand {
|
||||
public:
|
||||
ResizeLayout(RegionMap *map, int oldWidth, int oldHeight, int newWidth, int newHeight,
|
||||
QMap<QString, QList<LayoutSquare>> oldLayouts, QMap<QString, QList<LayoutSquare>> newLayouts, QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
bool mergeWith(const QUndoCommand *command) override;
|
||||
int id() const override { return RMCommandId::ID_ResizeLayout; }
|
||||
|
||||
private:
|
||||
RegionMap *map;
|
||||
|
||||
int oldWidth;
|
||||
int oldHeight;
|
||||
int newWidth;
|
||||
int newHeight;
|
||||
QMap<QString, QList<LayoutSquare>> oldLayouts;
|
||||
QMap<QString, QList<LayoutSquare>> newLayouts;
|
||||
};
|
||||
|
||||
|
||||
/// Edit Entry Value
|
||||
class EditEntry : public QUndoCommand {
|
||||
public:
|
||||
EditEntry(RegionMap *map, QString section, MapSectionEntry oldEntry, MapSectionEntry newEntry, QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
bool mergeWith(const QUndoCommand *command) override;
|
||||
int id() const override { return RMCommandId::ID_EditEntry; }
|
||||
|
||||
protected:
|
||||
RegionMap *map;
|
||||
|
||||
QString section;
|
||||
MapSectionEntry oldEntry;
|
||||
MapSectionEntry newEntry;
|
||||
};
|
||||
|
||||
|
||||
/// Remove Entry
|
||||
class RemoveEntry : public EditEntry {
|
||||
public:
|
||||
RemoveEntry(RegionMap *map, QString section, MapSectionEntry oldEntry, MapSectionEntry newEntry, QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return RMCommandId::ID_RemoveEntry; }
|
||||
};
|
||||
|
||||
|
||||
/// Add Entry
|
||||
class AddEntry : public EditEntry {
|
||||
public:
|
||||
AddEntry(RegionMap *map, QString section, MapSectionEntry oldEntry, MapSectionEntry newEntry, QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return RMCommandId::ID_AddEntry; }
|
||||
};
|
||||
|
||||
|
||||
/// ResizeTilemap
|
||||
class ResizeTilemap : public EditTilemap {
|
||||
public:
|
||||
ResizeTilemap(RegionMap *map, QByteArray oldTilemap, QByteArray newTilemap,
|
||||
int oldWidth, int oldHeight, int newWidth, int newHeight, QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
int id() const override { return RMCommandId::ID_ResizeTilemap; }
|
||||
|
||||
private:
|
||||
int oldWidth;
|
||||
int oldHeight;
|
||||
int newWidth;
|
||||
int newHeight;
|
||||
};
|
||||
|
||||
|
||||
/// ClearEntries
|
||||
class ClearEntries : public QUndoCommand {
|
||||
public:
|
||||
ClearEntries(RegionMap *map, tsl::ordered_map<QString, MapSectionEntry>, QUndoCommand *parent = nullptr);
|
||||
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
|
||||
bool mergeWith(const QUndoCommand *command) override { return false; }
|
||||
int id() const override { return RMCommandId::ID_ClearEntries; }
|
||||
|
||||
private:
|
||||
RegionMap *map;
|
||||
tsl::ordered_map<QString, MapSectionEntry> entries;
|
||||
};
|
||||
|
||||
#endif // REGIONMAPEDITCOMMANDS_H
|
|
@ -22,4 +22,15 @@ public:
|
|||
static int getIndexInTileset(int);
|
||||
};
|
||||
|
||||
inline bool operator==(const Tile &a, const Tile &b) {
|
||||
return a.tileId == b.tileId &&
|
||||
a.xflip == b.xflip &&
|
||||
a.yflip == b.yflip &&
|
||||
a.palette == b.palette;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Tile &a, const Tile &b) {
|
||||
return !(operator==(a, b));
|
||||
}
|
||||
|
||||
#endif // TILE_H
|
||||
|
|
|
@ -210,7 +210,7 @@ signals:
|
|||
void selectedObjectsChanged();
|
||||
void loadMapRequested(QString, QString);
|
||||
void wildMonDataChanged();
|
||||
void warpEventDoubleClicked(QString mapName, QString warpNum);
|
||||
void warpEventDoubleClicked(QString, QString, QString);
|
||||
void currentMetatilesSelectionChanged();
|
||||
void mapRulerStatusChanged(const QString &);
|
||||
void editedMapData();
|
||||
|
|
|
@ -212,7 +212,7 @@ private slots:
|
|||
void on_action_Reload_Project_triggered();
|
||||
void on_mapList_activated(const QModelIndex &index);
|
||||
void on_action_Save_Project_triggered();
|
||||
void openWarpMap(QString map_name, QString warp_num);
|
||||
void openWarpMap(QString map_name, QString event_id, QString event_group);
|
||||
|
||||
void duplicate();
|
||||
void setClipboardData(poryjson::Json::object);
|
||||
|
@ -345,7 +345,7 @@ private:
|
|||
QPointer<RegionMapEditor> regionMapEditor = nullptr;
|
||||
QPointer<ShortcutsEditor> shortcutsEditor = nullptr;
|
||||
QPointer<MapImageExporter> mapImageExporter = nullptr;
|
||||
QPointer<NewMapPopup> newmapprompt = nullptr;
|
||||
QPointer<NewMapPopup> newMapPrompt = nullptr;
|
||||
QPointer<PreferenceEditor> preferenceEditor = nullptr;
|
||||
FilterChildrenProxyModel *mapListProxyModel;
|
||||
QStandardItemModel *mapListModel;
|
||||
|
@ -418,6 +418,7 @@ private:
|
|||
void initShortcuts();
|
||||
void initExtraShortcuts();
|
||||
void setProjectSpecificUIVisibility();
|
||||
void setWildEncountersUIEnabled(bool enabled);
|
||||
void loadUserSettings();
|
||||
void applyMapListFilter(QString filterText);
|
||||
void restoreWindowState();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "wildmoninfo.h"
|
||||
#include "parseutil.h"
|
||||
#include "orderedjson.h"
|
||||
#include "regionmap.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QList>
|
||||
|
@ -60,7 +61,7 @@ public:
|
|||
QMap<QString, int> mapSectionNameToValue;
|
||||
QMap<int, QString> mapSectionValueToName;
|
||||
QMap<QString, EventGraphics*> eventGraphicsMap;
|
||||
QStringList gfxNames;
|
||||
QMap<QString, int> gfxDefines;
|
||||
QStringList songNames;
|
||||
QStringList itemNames;
|
||||
QStringList flagNames;
|
||||
|
@ -244,6 +245,7 @@ signals:
|
|||
void reloadProject();
|
||||
void uncheckMonitorFilesAction();
|
||||
void mapCacheCleared();
|
||||
void disableWildEncountersUI();
|
||||
};
|
||||
|
||||
#endif // PROJECT_H
|
||||
|
|
|
@ -11,6 +11,7 @@ public:
|
|||
explicit NewEventToolButton(QWidget *parent = nullptr);
|
||||
QString getSelectedEventType();
|
||||
QAction *newObjectAction;
|
||||
QAction *newCloneObjectAction;
|
||||
QAction *newWarpAction;
|
||||
QAction *newHealLocationAction;
|
||||
QAction *newTriggerAction;
|
||||
|
@ -20,6 +21,7 @@ public:
|
|||
QAction *newSecretBaseAction;
|
||||
public slots:
|
||||
void newObject();
|
||||
void newCloneObject();
|
||||
void newWarp();
|
||||
void newHealLocation();
|
||||
void newTrigger();
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "regionmaplayoutpixmapitem.h"
|
||||
#include "regionmapentriespixmapitem.h"
|
||||
#include "regionmap.h"
|
||||
#include "orderedjson.h"
|
||||
#include "project.h"
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
|
@ -24,14 +26,9 @@ public:
|
|||
explicit RegionMapEditor(QWidget *parent = 0, Project *pro = nullptr);
|
||||
~RegionMapEditor();
|
||||
|
||||
RegionMap *region_map;
|
||||
|
||||
bool loadRegionMapData();
|
||||
bool loadCityMaps();
|
||||
void setCurrentSquareOptions();
|
||||
bool load();
|
||||
|
||||
void onRegionMapTileSelectorSelectedTileChanged(unsigned id);
|
||||
void onCityMapTileSelectorSelectedTileChanged(unsigned id);
|
||||
void onRegionMapTileSelectorHoveredTileChanged(unsigned id);
|
||||
void onRegionMapTileSelectorHoveredTileCleared();
|
||||
|
||||
|
@ -42,10 +39,7 @@ public:
|
|||
void onRegionMapEntriesSelectedTileChanged(QString) {};
|
||||
void onRegionMapEntryDragged(int, int);
|
||||
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
void resize(int width, int height);
|
||||
void resizeTilemap(int width, int height);
|
||||
|
||||
QObjectList shortcutableObjects() const;
|
||||
|
||||
|
@ -56,14 +50,19 @@ private:
|
|||
Ui::RegionMapEditor *ui;
|
||||
Project *project;
|
||||
|
||||
History<RegionMapHistoryItem*> history;
|
||||
RegionMap *region_map = nullptr;
|
||||
tsl::ordered_map<QString, RegionMap *> region_maps;
|
||||
|
||||
int currIndex;
|
||||
unsigned selectedCityTile;
|
||||
unsigned selectedImageTile;
|
||||
poryjson::Json rmConfigJson;
|
||||
|
||||
bool configSaved = false;
|
||||
|
||||
QUndoGroup history;
|
||||
|
||||
int currIndex = 0;
|
||||
unsigned selectedImageTile = 0;
|
||||
QString activeEntry;
|
||||
|
||||
bool hasUnsavedChanges = false;
|
||||
bool cityMapFirstDraw = true;
|
||||
bool regionMapFirstDraw = true;
|
||||
bool entriesFirstDraw = true;
|
||||
|
@ -72,19 +71,32 @@ private:
|
|||
double initialScale = 30.0;
|
||||
|
||||
QGraphicsScene *scene_region_map_image = nullptr;
|
||||
QGraphicsScene *scene_city_map_image = nullptr;
|
||||
QGraphicsScene *scene_region_map_layout = nullptr;
|
||||
QGraphicsScene *scene_region_map_entries = nullptr;
|
||||
QGraphicsScene *scene_region_map_tiles = nullptr;
|
||||
QGraphicsScene *scene_city_map_tiles = nullptr;
|
||||
|
||||
TilemapTileSelector *mapsquare_selector_item = nullptr;
|
||||
TilemapTileSelector *city_map_selector_item = nullptr;
|
||||
|
||||
RegionMapEntriesPixmapItem *region_map_entries_item = nullptr;
|
||||
RegionMapLayoutPixmapItem *region_map_layout_item = nullptr;
|
||||
RegionMapPixmapItem *region_map_item = nullptr;
|
||||
CityMapPixmapItem *city_map_item = nullptr;
|
||||
|
||||
bool reload();
|
||||
bool setup();
|
||||
void clear();
|
||||
|
||||
bool saveRegionMap(RegionMap *map);
|
||||
void saveConfig();
|
||||
bool loadRegionMapEntries();
|
||||
bool saveRegionMapEntries();
|
||||
tsl::ordered_map<QString, MapSectionEntry> region_map_entries;
|
||||
|
||||
bool buildConfigDialog();
|
||||
poryjson::Json configRegionMapDialog();
|
||||
poryjson::Json buildDefaultJson();
|
||||
bool verifyConfig(poryjson::Json cfg);
|
||||
|
||||
bool modified();
|
||||
|
||||
void initShortcuts();
|
||||
void displayRegionMap();
|
||||
|
@ -94,47 +106,46 @@ private:
|
|||
void displayRegionMapLayoutOptions();
|
||||
void updateRegionMapLayoutOptions(int index);
|
||||
void displayRegionMapTileSelector();
|
||||
void displayCityMapTileSelector();
|
||||
void displayCityMap(QString name);
|
||||
void updateLayerDisplayed();
|
||||
void displayRegionMapEntryOptions();
|
||||
void updateRegionMapEntryOptions(QString);
|
||||
void importTileImage(bool city = false);
|
||||
|
||||
bool createCityMap(QString name);
|
||||
bool tryInsertNewMapEntry(QString);
|
||||
void setRegionMap(RegionMap *map);
|
||||
|
||||
void restoreWindowState();
|
||||
void closeEvent(QCloseEvent* event);
|
||||
|
||||
private slots:
|
||||
void on_action_RegionMap_Save_triggered();
|
||||
void on_action_RegionMap_Undo_triggered();
|
||||
void on_action_RegionMap_Redo_triggered();
|
||||
void on_actionSave_All_triggered();
|
||||
void on_action_RegionMap_Resize_triggered();
|
||||
void on_action_RegionMap_ClearImage_triggered();
|
||||
void on_action_RegionMap_ClearLayout_triggered();
|
||||
void on_action_RegionMap_ClearEntries_triggered();
|
||||
void on_action_Swap_triggered();
|
||||
void on_action_Import_RegionMap_ImageTiles_triggered();
|
||||
void on_action_Import_CityMap_ImageTiles_triggered();
|
||||
void on_action_Replace_triggered();
|
||||
void on_action_Configure_triggered();
|
||||
void on_tabWidget_Region_Map_currentChanged(int);
|
||||
void on_pushButton_RM_Options_delete_clicked();
|
||||
void on_comboBox_RM_ConnectedMap_textActivated(const QString &);
|
||||
void on_comboBox_RM_Entry_MapSection_textActivated(const QString &);
|
||||
void on_comboBox_regionSelector_textActivated(const QString &);
|
||||
void on_comboBox_layoutLayer_textActivated(const QString &);
|
||||
void on_spinBox_RM_Entry_x_valueChanged(int);
|
||||
void on_spinBox_RM_Entry_y_valueChanged(int);
|
||||
void on_spinBox_RM_Entry_width_valueChanged(int);
|
||||
void on_spinBox_RM_Entry_height_valueChanged(int);
|
||||
void on_pushButton_CityMap_add_clicked();
|
||||
void on_pushButton_entryActivate_clicked();
|
||||
void on_spinBox_RM_LayoutWidth_valueChanged(int);
|
||||
void on_spinBox_RM_LayoutHeight_valueChanged(int);
|
||||
void on_spinBox_tilePalette_valueChanged(int);
|
||||
void on_checkBox_tileHFlip_stateChanged(int);
|
||||
void on_checkBox_tileVFlip_stateChanged(int);
|
||||
void on_verticalSlider_Zoom_Map_Image_valueChanged(int);
|
||||
void on_verticalSlider_Zoom_Image_Tiles_valueChanged(int);
|
||||
void on_verticalSlider_Zoom_City_Map_valueChanged(int);
|
||||
void on_verticalSlider_Zoom_City_Tiles_valueChanged(int);
|
||||
void on_comboBox_CityMap_picker_currentTextChanged(const QString &);
|
||||
void on_lineEdit_RM_MapName_textEdited(const QString &);
|
||||
void onHoveredRegionMapTileChanged(int x, int y);
|
||||
void onHoveredRegionMapTileCleared();
|
||||
void mouseEvent_region_map(QGraphicsSceneMouseEvent *event, RegionMapPixmapItem *item);
|
||||
void mouseEvent_city_map(QGraphicsSceneMouseEvent *event, CityMapPixmapItem *item);
|
||||
};
|
||||
|
||||
#endif // REGIONMAPEDITOR_H
|
||||
|
|
|
@ -17,12 +17,14 @@ public:
|
|||
this->tile_selector = tile_selector;
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
RegionMap *region_map;
|
||||
RegionMap *region_map = nullptr;
|
||||
TilemapTileSelector *tile_selector;
|
||||
|
||||
virtual void paint(QGraphicsSceneMouseEvent *);
|
||||
virtual void fill(QGraphicsSceneMouseEvent *);
|
||||
virtual void select(QGraphicsSceneMouseEvent *);
|
||||
virtual void draw();
|
||||
void floodFill(int x, int y, std::shared_ptr<TilemapTile> oldTile, std::shared_ptr<TilemapTile> newTile);
|
||||
|
||||
signals:
|
||||
void mouseEvent(QGraphicsSceneMouseEvent *, RegionMapPixmapItem *);
|
||||
|
|
47
include/ui/regionmappropertiesdialog.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef REGIONMAPPROPERTIESDIALOG_H
|
||||
#define REGIONMAPPROPERTIESDIALOG_H
|
||||
|
||||
#include "orderedjson.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFileDialog>
|
||||
|
||||
class Project;
|
||||
|
||||
namespace Ui {
|
||||
class RegionMapPropertiesDialog;
|
||||
}
|
||||
|
||||
class RegionMapPropertiesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RegionMapPropertiesDialog(QWidget *parent = nullptr);
|
||||
~RegionMapPropertiesDialog();
|
||||
|
||||
void setProject(Project *project) { this->project = project; }
|
||||
|
||||
void setProperties(poryjson::Json object);
|
||||
poryjson::Json saveToJson();
|
||||
|
||||
virtual void accept() override;
|
||||
|
||||
private:
|
||||
Ui::RegionMapPropertiesDialog *ui;
|
||||
Project *project = nullptr;
|
||||
|
||||
void hideMessages();
|
||||
|
||||
QString browse(QString filter, QFileDialog::FileMode mode);
|
||||
|
||||
private slots:
|
||||
void on_browse_tilesetImagePath_clicked();
|
||||
void on_browse_tilemapBinPath_clicked();
|
||||
void on_browse_tilemapPalettePath_clicked();
|
||||
void on_browse_layoutPath_clicked();
|
||||
|
||||
//void on_buttonBox_accepted();
|
||||
};
|
||||
|
||||
#endif // REGIONMAPPROPERTIESDIALOG_H
|
|
@ -1,29 +1,165 @@
|
|||
#pragma once
|
||||
#ifndef TILEMAPTILESELECTOR_H
|
||||
#define TILEMAPTILESELECTOR_H
|
||||
|
||||
#include "selectablepixmapitem.h"
|
||||
#include "paletteutil.h"
|
||||
|
||||
#include <memory>
|
||||
using std::shared_ptr;
|
||||
|
||||
enum class TilemapFormat { Plain, BPP_4, BPP_8 };
|
||||
|
||||
class TilemapTile {
|
||||
unsigned raw_ = 0;
|
||||
unsigned id_ = 0;
|
||||
bool hFlip_ = false;
|
||||
bool vFlip_ = false;
|
||||
int palette_ = 0;
|
||||
|
||||
protected:
|
||||
TilemapTile(unsigned raw, unsigned id, bool hFlip, bool vFlip, int palette) : raw_(raw), id_(id), hFlip_(hFlip), vFlip_(vFlip), palette_(palette) {}
|
||||
virtual ~TilemapTile() {}
|
||||
|
||||
public:
|
||||
TilemapTile()=default;
|
||||
|
||||
TilemapTile(TilemapTile &other) {
|
||||
this->raw_ = other.raw();
|
||||
this->id_ = other.id();
|
||||
this->hFlip_ = other.hFlip();
|
||||
this->vFlip_ = other.vFlip();
|
||||
this->palette_ = other.palette();
|
||||
}
|
||||
|
||||
TilemapTile &operator=(const TilemapTile &other) {
|
||||
this->raw_ = other.raw();
|
||||
this->id_ = other.id();
|
||||
this->hFlip_ = other.hFlip();
|
||||
this->vFlip_ = other.vFlip();
|
||||
this->palette_ = other.palette();
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual void copy(TilemapTile &other) {
|
||||
this->raw_ = other.raw();
|
||||
this->id_ = other.id();
|
||||
this->hFlip_ = other.hFlip();
|
||||
this->vFlip_ = other.vFlip();
|
||||
this->palette_ = other.palette();
|
||||
}
|
||||
|
||||
virtual unsigned raw() const { return this->raw_; }
|
||||
virtual unsigned id() const { return this->id_; }
|
||||
virtual bool hFlip() const { return this->hFlip_; }
|
||||
virtual bool vFlip() const { return this->vFlip_; }
|
||||
virtual int palette() const { return this->palette_; }
|
||||
|
||||
virtual void setId(unsigned id) { this->id_ = id; }
|
||||
virtual void setHFlip(bool hFlip) { this->hFlip_ = hFlip; }
|
||||
virtual void setVFlip(bool vFlip) { this->vFlip_ = vFlip; }
|
||||
virtual void setPalette(int palette) { this->palette_ = palette; }
|
||||
|
||||
bool operator==(const TilemapTile& other) {
|
||||
return (this->raw() == other.raw());
|
||||
}
|
||||
|
||||
virtual QString info() const {
|
||||
return QString("Tile: 0x") + QString("%1 ").arg(this->id(), 4, 16, QChar('0')).toUpper();
|
||||
}
|
||||
};
|
||||
|
||||
class PlainTile : public TilemapTile {
|
||||
public:
|
||||
PlainTile(unsigned raw) : TilemapTile(raw, raw, false, false, 0) {}
|
||||
|
||||
~PlainTile() {}
|
||||
|
||||
virtual unsigned raw () const override { return id(); }
|
||||
};
|
||||
|
||||
class BPP4Tile : public TilemapTile {
|
||||
public:
|
||||
BPP4Tile(unsigned raw) : TilemapTile(
|
||||
raw,
|
||||
raw & 0x3ff, // tileId
|
||||
!!(raw & 0x0400), // hFlip
|
||||
!!(raw & 0x0800), // vFlip
|
||||
(raw & 0xf000) >> 12 // palette
|
||||
) {}
|
||||
|
||||
~BPP4Tile() {}
|
||||
|
||||
virtual unsigned raw () const override {
|
||||
return (id()) | (hFlip() << 10) | (vFlip() << 11) | (palette() << 12);
|
||||
}
|
||||
|
||||
virtual QString info() const override {
|
||||
return TilemapTile::info() + QString("hFlip: %1 vFlip: %2 palette: %3").arg(this->hFlip()).arg(this->vFlip()).arg(this->palette());
|
||||
}
|
||||
};
|
||||
|
||||
class BPP8Tile : public TilemapTile {
|
||||
public:
|
||||
BPP8Tile(unsigned raw) : TilemapTile(
|
||||
raw,
|
||||
raw & 0x3ff, // tileId
|
||||
!!(raw & 0x0400), // hFlip
|
||||
!!(raw & 0x0800), // vFlip
|
||||
0 // palette
|
||||
) {}
|
||||
|
||||
~BPP8Tile() {}
|
||||
|
||||
virtual unsigned raw () const override {
|
||||
return (id()) | (hFlip() << 10) | (vFlip() << 11);
|
||||
}
|
||||
|
||||
virtual QString info() const override {
|
||||
return TilemapTile::info() + QString("hFlip: %1 vFlip: %2").arg(this->hFlip()).arg(this->vFlip());
|
||||
}
|
||||
};
|
||||
|
||||
class TilemapTileSelector: public SelectablePixmapItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TilemapTileSelector(QPixmap pixmap_): SelectablePixmapItem(8, 8, 1, 1) {
|
||||
this->tilemap = pixmap_;
|
||||
this->setPixmap(this->tilemap);
|
||||
this->numTilesWide = tilemap.width() / 8;
|
||||
TilemapTileSelector(QString tilesetFilepath, TilemapFormat format, QString palFilepath): SelectablePixmapItem(8, 8, 1, 1) {
|
||||
this->tileset = QImage(tilesetFilepath);
|
||||
this->format = format;
|
||||
bool err;
|
||||
if (!palFilepath.isEmpty()) {
|
||||
this->palette = PaletteUtil::parse(palFilepath, &err);
|
||||
}
|
||||
this->setPixmap(QPixmap::fromImage(this->tileset));
|
||||
this->numTilesWide = this->tileset.width() / 8;
|
||||
this->selectedTile = 0x00;
|
||||
setAcceptHoverEvents(true);
|
||||
}
|
||||
void draw();
|
||||
void select(unsigned tileId);
|
||||
unsigned getSelectedTile();
|
||||
QImage setPalette(int index);
|
||||
|
||||
int pixelWidth;
|
||||
int pixelHeight;
|
||||
|
||||
void select(unsigned tileId);
|
||||
unsigned selectedTile = 0;
|
||||
|
||||
QPixmap tilemap;
|
||||
QImage tileImg(unsigned tileId);
|
||||
void selectVFlip(bool hFlip) { this->tile_hFlip = hFlip; }
|
||||
bool tile_hFlip = false;
|
||||
|
||||
void selectHFlip(bool vFlip) { this->tile_vFlip = vFlip; }
|
||||
bool tile_vFlip = false;
|
||||
|
||||
void selectPalette(int palette) {
|
||||
this->tile_palette = palette;
|
||||
this->draw();
|
||||
}
|
||||
int tile_palette = 0;
|
||||
|
||||
QImage tileset;
|
||||
TilemapFormat format = TilemapFormat::Plain;
|
||||
QList<QRgb> palette;
|
||||
QImage tileImg(shared_ptr<TilemapTile> tile);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent*);
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
void updateMap(Map *map);
|
||||
void updateTilesets(QString primaryTilsetLabel, QString secondaryTilesetLabel);
|
||||
bool selectMetatile(uint16_t metatileId);
|
||||
uint16_t getSelectedMetatile();
|
||||
uint16_t getSelectedMetatileId();
|
||||
void setMetatileLabel(QString label);
|
||||
|
||||
QObjectList shortcutableObjects() const;
|
||||
|
@ -105,6 +105,10 @@ private slots:
|
|||
|
||||
void on_copyButton_metatileLabel_clicked();
|
||||
|
||||
void on_actionCopy_triggered();
|
||||
|
||||
void on_actionPaste_triggered();
|
||||
|
||||
private:
|
||||
void initUi();
|
||||
void setMetatileBehaviors();
|
||||
|
@ -129,6 +133,7 @@ private:
|
|||
void closeEvent(QCloseEvent*);
|
||||
void countMetatileUsage();
|
||||
void countTileUsage();
|
||||
bool replaceMetatile(uint16_t metatileId, Metatile * src);
|
||||
|
||||
Ui::TilesetEditor *ui;
|
||||
History<MetatileHistoryItem*> metatileHistory;
|
||||
|
@ -139,6 +144,7 @@ private:
|
|||
Project *project = nullptr;
|
||||
Map *map = nullptr;
|
||||
Metatile *metatile = nullptr;
|
||||
Metatile *copiedMetatile = nullptr;
|
||||
int paletteId;
|
||||
bool tileXFlip;
|
||||
bool tileYFlip;
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
void draw();
|
||||
bool select(uint16_t metatileId);
|
||||
void setTilesets(Tileset*, Tileset*, bool draw = true);
|
||||
uint16_t getSelectedMetatile();
|
||||
uint16_t getSelectedMetatileId();
|
||||
void updateSelectedMetatile();
|
||||
QPoint getMetatileIdCoordsOnWidget(uint16_t metatileId);
|
||||
|
||||
|
|
12
porymap.pro
|
@ -12,7 +12,7 @@ TARGET = porymap
|
|||
TEMPLATE = app
|
||||
RC_ICONS = resources/icons/porymap-icon-2.ico
|
||||
ICON = resources/icons/porymap.icns
|
||||
QMAKE_CXXFLAGS += -std=c++11 -Wall
|
||||
QMAKE_CXXFLAGS += -std=c++17 -Wall
|
||||
QMAKE_TARGET_BUNDLE_PREFIX = com.pret
|
||||
|
||||
SOURCES += src/core/block.cpp \
|
||||
|
@ -33,6 +33,7 @@ SOURCES += src/core/block.cpp \
|
|||
src/core/wildmoninfo.cpp \
|
||||
src/core/editcommands.cpp \
|
||||
src/lib/orderedjson.cpp \
|
||||
src/core/regionmapeditcommands.cpp \
|
||||
src/mainwindow_scriptapi.cpp \
|
||||
src/ui/aboutporymap.cpp \
|
||||
src/ui/draggablepixmapitem.cpp \
|
||||
|
@ -77,6 +78,7 @@ SOURCES += src/core/block.cpp \
|
|||
src/ui/shortcutseditor.cpp \
|
||||
src/ui/multikeyedit.cpp \
|
||||
src/ui/preferenceeditor.cpp \
|
||||
src/ui/regionmappropertiesdialog.cpp \
|
||||
src/config.cpp \
|
||||
src/editor.cpp \
|
||||
src/main.cpp \
|
||||
|
@ -105,6 +107,7 @@ HEADERS += include/core/block.h \
|
|||
include/core/regionmap.h \
|
||||
include/core/wildmoninfo.h \
|
||||
include/core/editcommands.h \
|
||||
include/core/regionmapeditcommands.h \
|
||||
include/lib/orderedmap.h \
|
||||
include/lib/orderedjson.h \
|
||||
include/ui/aboutporymap.h \
|
||||
|
@ -151,6 +154,7 @@ HEADERS += include/core/block.h \
|
|||
include/ui/shortcutseditor.h \
|
||||
include/ui/multikeyedit.h \
|
||||
include/ui/preferenceeditor.h \
|
||||
include/ui/regionmappropertiesdialog.h \
|
||||
include/config.h \
|
||||
include/editor.h \
|
||||
include/mainwindow.h \
|
||||
|
@ -169,11 +173,13 @@ FORMS += forms/mainwindow.ui \
|
|||
forms/newtilesetdialog.ui \
|
||||
forms/mapimageexporter.ui \
|
||||
forms/shortcutseditor.ui \
|
||||
forms/preferenceeditor.ui
|
||||
forms/preferenceeditor.ui \
|
||||
forms/regionmappropertiesdialog.ui
|
||||
|
||||
RESOURCES += \
|
||||
resources/images.qrc \
|
||||
resources/themes.qrc
|
||||
resources/themes.qrc \
|
||||
resources/text.qrc
|
||||
|
||||
INCLUDEPATH += include
|
||||
INCLUDEPATH += include/core
|
||||
|
|
BIN
resources/icons/empty_cross_cursor.ico
Normal file
After Width: | Height: | Size: 574 B |
BIN
resources/icons/pencil_bw.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 490 B After Width: | Height: | Size: 4.3 KiB |
7
resources/text.qrc
Normal file
|
@ -0,0 +1,7 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>text/region_map_default_emerald.json</file>
|
||||
<file>text/region_map_default_firered.json</file>
|
||||
<file>text/region_map_default_ruby.json</file>
|
||||
</qresource>
|
||||
</RCC>
|
33
resources/text/region_map_default_emerald.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"region_maps": [
|
||||
{
|
||||
"alias": "hoenn",
|
||||
"tilemap": {
|
||||
"width": 64,
|
||||
"height": 64,
|
||||
"format": "plain",
|
||||
"tileset_path": "graphics/pokenav/region_map.png",
|
||||
"tilemap_path": "graphics/pokenav/region_map_map.bin"
|
||||
},
|
||||
"layout": {
|
||||
"width": 28,
|
||||
"height": 15,
|
||||
"offset_left": 1,
|
||||
"offset_top": 2,
|
||||
"format": "C array",
|
||||
"path": "src/data/region_map/region_map_layout.h"
|
||||
}
|
||||
},
|
||||
{
|
||||
"alias": "pokedex area screen",
|
||||
"tilemap": {
|
||||
"width": 32,
|
||||
"height": 32,
|
||||
"format": "8bpp",
|
||||
"tileset_path": "graphics/pokedex/region_map.png",
|
||||
"tilemap_path": "graphics/pokedex/region_map.bin"
|
||||
},
|
||||
"layout": null
|
||||
}
|
||||
]
|
||||
}
|
80
resources/text/region_map_default_firered.json
Normal file
|
@ -0,0 +1,80 @@
|
|||
{
|
||||
"region_maps": [
|
||||
{
|
||||
"alias": "kanto",
|
||||
"tilemap": {
|
||||
"width": 30,
|
||||
"height": 20,
|
||||
"format": "4bpp",
|
||||
"tileset_path": "graphics/region_map/region_map.png",
|
||||
"tilemap_path": "graphics/region_map/kanto.bin",
|
||||
"palette": "graphics/region_map/region_map.pal"
|
||||
},
|
||||
"layout": {
|
||||
"width": 22,
|
||||
"height": 15,
|
||||
"offset_left": 4,
|
||||
"offset_top": 4,
|
||||
"format": "C array",
|
||||
"path": "src/data/region_map/region_map_layout_kanto.h"
|
||||
}
|
||||
},
|
||||
{
|
||||
"alias": "sevii_123",
|
||||
"tilemap": {
|
||||
"width": 30,
|
||||
"height": 20,
|
||||
"format": "4bpp",
|
||||
"tileset_path": "graphics/region_map/region_map.png",
|
||||
"tilemap_path": "graphics/region_map/sevii_123.bin",
|
||||
"palette": "graphics/region_map/region_map.pal"
|
||||
},
|
||||
"layout": {
|
||||
"width": 22,
|
||||
"height": 15,
|
||||
"offset_left": 4,
|
||||
"offset_top": 4,
|
||||
"format": "C array",
|
||||
"path": "src/data/region_map/region_map_layout_sevii_123.h"
|
||||
}
|
||||
},
|
||||
{
|
||||
"alias": "sevii_45",
|
||||
"tilemap": {
|
||||
"width": 30,
|
||||
"height": 20,
|
||||
"format": "4bpp",
|
||||
"tileset_path": "graphics/region_map/region_map.png",
|
||||
"tilemap_path": "graphics/region_map/sevii_45.bin",
|
||||
"palette": "graphics/region_map/region_map.pal"
|
||||
},
|
||||
"layout": {
|
||||
"width": 22,
|
||||
"height": 15,
|
||||
"offset_left": 4,
|
||||
"offset_top": 4,
|
||||
"format": "C array",
|
||||
"path": "src/data/region_map/region_map_layout_sevii_45.h"
|
||||
}
|
||||
},
|
||||
{
|
||||
"alias": "sevii_67",
|
||||
"tilemap": {
|
||||
"width": 30,
|
||||
"height": 20,
|
||||
"format": "4bpp",
|
||||
"tileset_path": "graphics/region_map/region_map.png",
|
||||
"tilemap_path": "graphics/region_map/sevii_67.bin",
|
||||
"palette": "graphics/region_map/region_map.pal"
|
||||
},
|
||||
"layout": {
|
||||
"width": 22,
|
||||
"height": 15,
|
||||
"offset_left": 4,
|
||||
"offset_top": 4,
|
||||
"format": "C array",
|
||||
"path": "src/data/region_map/region_map_layout_sevii_67.h"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
22
resources/text/region_map_default_ruby.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"region_maps": [
|
||||
{
|
||||
"alias": "hoenn",
|
||||
"tilemap": {
|
||||
"width": 64,
|
||||
"height": 64,
|
||||
"format": "plain",
|
||||
"tileset_path": "graphics/pokenav/region_map.png",
|
||||
"tilemap_path": "graphics/pokenav/region_map_map.bin"
|
||||
},
|
||||
"layout": {
|
||||
"width": 28,
|
||||
"height": 15,
|
||||
"offset_left": 1,
|
||||
"offset_top": 2,
|
||||
"format": "C array",
|
||||
"path": "src/data/region_map/region_map_layout.h"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -522,11 +522,11 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
|||
if (!ok) {
|
||||
logWarn(QString("Invalid config value for enable_heal_location_respawn_data: '%1'. Must be 0 or 1.").arg(value));
|
||||
}
|
||||
} else if (key == "enable_object_event_in_connection") {
|
||||
} else if (key == "enable_event_clone_object") {
|
||||
bool ok;
|
||||
this->enableObjectEventInConnection = value.toInt(&ok);
|
||||
this->enableEventCloneObject = value.toInt(&ok);
|
||||
if (!ok) {
|
||||
logWarn(QString("Invalid config value for enable_object_event_in_connection: '%1'. Must be 0 or 1.").arg(value));
|
||||
logWarn(QString("Invalid config value for enable_event_clone_object: '%1'. Must be 0 or 1.").arg(value));
|
||||
}
|
||||
} else if (key == "enable_floor_number") {
|
||||
bool ok;
|
||||
|
@ -570,7 +570,7 @@ void ProjectConfig::setUnreadKeys() {
|
|||
if (!readKeys.contains("enable_hidden_item_quantity")) this->enableHiddenItemQuantity = isPokefirered;
|
||||
if (!readKeys.contains("enable_hidden_item_requires_itemfinder")) this->enableHiddenItemRequiresItemfinder = isPokefirered;
|
||||
if (!readKeys.contains("enable_heal_location_respawn_data")) this->enableHealLocationRespawnData = isPokefirered;
|
||||
if (!readKeys.contains("enable_object_event_in_connection")) this->enableObjectEventInConnection = isPokefirered;
|
||||
if (!readKeys.contains("enable_event_clone_object")) this->enableEventCloneObject = isPokefirered;
|
||||
if (!readKeys.contains("enable_floor_number")) this->enableFloorNumber = isPokefirered;
|
||||
if (!readKeys.contains("create_map_text_file")) this->createMapTextFile = (this->baseGameVersion != BaseGameVersion::pokeemerald);
|
||||
}
|
||||
|
@ -587,7 +587,7 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
|
|||
map.insert("enable_hidden_item_quantity", QString::number(this->enableHiddenItemQuantity));
|
||||
map.insert("enable_hidden_item_requires_itemfinder", QString::number(this->enableHiddenItemRequiresItemfinder));
|
||||
map.insert("enable_heal_location_respawn_data", QString::number(this->enableHealLocationRespawnData));
|
||||
map.insert("enable_object_event_in_connection", QString::number(this->enableObjectEventInConnection));
|
||||
map.insert("enable_event_clone_object", QString::number(this->enableEventCloneObject));
|
||||
map.insert("enable_floor_number", QString::number(this->enableFloorNumber));
|
||||
map.insert("create_map_text_file", QString::number(this->createMapTextFile));
|
||||
map.insert("enable_triple_layer_metatiles", QString::number(this->enableTripleLayerMetatiles));
|
||||
|
@ -628,7 +628,7 @@ void ProjectConfig::onNewConfigFileCreated() {
|
|||
this->enableHiddenItemQuantity = isPokefirered;
|
||||
this->enableHiddenItemRequiresItemfinder = isPokefirered;
|
||||
this->enableHealLocationRespawnData = isPokefirered;
|
||||
this->enableObjectEventInConnection = isPokefirered;
|
||||
this->enableEventCloneObject = isPokefirered;
|
||||
this->enableFloorNumber = isPokefirered;
|
||||
this->createMapTextFile = (this->baseGameVersion != BaseGameVersion::pokeemerald);
|
||||
this->useEncounterJson = true;
|
||||
|
@ -739,13 +739,13 @@ bool ProjectConfig::getHealLocationRespawnDataEnabled() {
|
|||
return this->enableHealLocationRespawnData;
|
||||
}
|
||||
|
||||
void ProjectConfig::setObjectEventInConnectionEnabled(bool enable) {
|
||||
this->enableObjectEventInConnection = enable;
|
||||
void ProjectConfig::setEventCloneObjectEnabled(bool enable) {
|
||||
this->enableEventCloneObject = enable;
|
||||
this->save();
|
||||
}
|
||||
|
||||
bool ProjectConfig::getObjectEventInConnectionEnabled() {
|
||||
return this->enableObjectEventInConnection;
|
||||
bool ProjectConfig::getEventCloneObjectEnabled() {
|
||||
return this->enableEventCloneObject;
|
||||
}
|
||||
|
||||
void ProjectConfig::setFloorNumberEnabled(bool enable) {
|
||||
|
|
|
@ -9,18 +9,16 @@
|
|||
int getEventTypeMask(QList<Event *> events) {
|
||||
int eventTypeMask = 0;
|
||||
for (auto event : events) {
|
||||
if (event->get("event_type") == EventType::Object) {
|
||||
QString groupType = event->get("event_group_type");
|
||||
if (groupType == EventGroup::Object) {
|
||||
eventTypeMask |= IDMask_EventType_Object;
|
||||
} else if (event->get("event_type") == EventType::Warp) {
|
||||
} else if (groupType == EventGroup::Warp) {
|
||||
eventTypeMask |= IDMask_EventType_Warp;
|
||||
} else if (event->get("event_type") == EventType::Trigger ||
|
||||
event->get("event_type") == EventType::WeatherTrigger) {
|
||||
} else if (groupType == EventGroup::Coord) {
|
||||
eventTypeMask |= IDMask_EventType_Trigger;
|
||||
} else if (event->get("event_type") == EventType::Sign ||
|
||||
event->get("event_type") == EventType::HiddenItem ||
|
||||
event->get("event_type") == EventType::SecretBase) {
|
||||
} else if (groupType == EventGroup::Bg) {
|
||||
eventTypeMask |= IDMask_EventType_BG;
|
||||
} else if (event->get("event_type") == EventType::HealLocation) {
|
||||
} else if (groupType == EventGroup::Heal) {
|
||||
eventTypeMask |= IDMask_EventType_Heal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,33 @@
|
|||
#include "project.h"
|
||||
#include "config.h"
|
||||
|
||||
QString EventGroup::Object = "object_event_group";
|
||||
QString EventGroup::Warp = "warp_event_group";
|
||||
QString EventGroup::Heal = "heal_event_group";
|
||||
QString EventGroup::Coord = "coord_event_group";
|
||||
QString EventGroup::Bg = "bg_event_group";
|
||||
|
||||
QString EventType::Object = "event_object";
|
||||
QString EventType::CloneObject = "event_clone_object";
|
||||
QString EventType::Warp = "event_warp";
|
||||
QString EventType::Trigger = "event_trigger";
|
||||
QString EventType::WeatherTrigger = "event_weather_trigger";
|
||||
QString EventType::Sign = "event_sign";
|
||||
QString EventType::HiddenItem = "event_hidden_item";
|
||||
QString EventType::SecretBase = "event_secret_base";
|
||||
QString EventType::HealLocation = "event_heal_location";
|
||||
QString EventType::HealLocation = "event_healspot";
|
||||
|
||||
const QMap<QString, QString> EventTypeTable = {
|
||||
{EventType::Object, EventGroup::Object},
|
||||
{EventType::CloneObject, EventGroup::Object},
|
||||
{EventType::Warp, EventGroup::Warp},
|
||||
{EventType::Trigger, EventGroup::Coord},
|
||||
{EventType::WeatherTrigger, EventGroup::Coord},
|
||||
{EventType::Sign, EventGroup::Bg},
|
||||
{EventType::HiddenItem, EventGroup::Bg},
|
||||
{EventType::SecretBase, EventGroup::Bg},
|
||||
{EventType::HealLocation, EventGroup::Heal},
|
||||
};
|
||||
|
||||
Event::Event() :
|
||||
spriteWidth(16),
|
||||
|
@ -41,6 +60,8 @@ Event* Event::createNewEvent(QString event_type, QString map_name, Project *proj
|
|||
if (event_type == EventType::Object) {
|
||||
event = createNewObjectEvent(project);
|
||||
event->setFrameFromMovement(event->get("movement_type"));
|
||||
} else if (event_type == EventType::CloneObject) {
|
||||
event = createNewCloneObjectEvent(project, map_name);
|
||||
} else if (event_type == EventType::Warp) {
|
||||
event = createNewWarpEvent(map_name);
|
||||
} else if (event_type == EventType::HealLocation) {
|
||||
|
@ -60,6 +81,8 @@ Event* Event::createNewEvent(QString event_type, QString map_name, Project *proj
|
|||
event = new Event;
|
||||
}
|
||||
|
||||
event->put("event_type", event_type);
|
||||
event->put("event_group_type", typeToGroup(event_type));
|
||||
event->setX(0);
|
||||
event->setY(0);
|
||||
return event;
|
||||
|
@ -68,13 +91,8 @@ Event* Event::createNewEvent(QString event_type, QString map_name, Project *proj
|
|||
Event* Event::createNewObjectEvent(Project *project)
|
||||
{
|
||||
Event *event = new Event;
|
||||
event->put("event_group_type", "object_event_group");
|
||||
event->put("event_type", EventType::Object);
|
||||
event->put("sprite", project->gfxNames.first());
|
||||
event->put("sprite", project->gfxDefines.keys().first());
|
||||
event->put("movement_type", project->movementTypes.first());
|
||||
if (projectConfig.getObjectEventInConnectionEnabled()) {
|
||||
event->put("in_connection", false);
|
||||
}
|
||||
event->put("radius_x", 0);
|
||||
event->put("radius_y", 0);
|
||||
event->put("script_label", "NULL");
|
||||
|
@ -86,11 +104,18 @@ Event* Event::createNewObjectEvent(Project *project)
|
|||
return event;
|
||||
}
|
||||
|
||||
Event* Event::createNewCloneObjectEvent(Project *project, QString map_name)
|
||||
{
|
||||
Event *event = new Event;
|
||||
event->put("sprite", project->gfxDefines.keys().first());
|
||||
event->put("target_local_id", 1);
|
||||
event->put("target_map", map_name);
|
||||
return event;
|
||||
}
|
||||
|
||||
Event* Event::createNewWarpEvent(QString map_name)
|
||||
{
|
||||
Event *event = new Event;
|
||||
event->put("event_group_type", "warp_event_group");
|
||||
event->put("event_type", EventType::Warp);
|
||||
event->put("destination_warp", 0);
|
||||
event->put("destination_map_name", map_name);
|
||||
event->put("elevation", 0);
|
||||
|
@ -100,8 +125,6 @@ Event* Event::createNewWarpEvent(QString map_name)
|
|||
Event* Event::createNewHealLocationEvent(QString map_name)
|
||||
{
|
||||
Event *event = new Event;
|
||||
event->put("event_group_type", "heal_event_group");
|
||||
event->put("event_type", EventType::HealLocation);
|
||||
event->put("loc_name", QString(Map::mapConstantFromName(map_name)).remove(0,4));
|
||||
event->put("id_name", map_name.replace(QRegularExpression("([a-z])([A-Z])"), "\\1_\\2").toUpper());
|
||||
event->put("elevation", 3);
|
||||
|
@ -115,8 +138,6 @@ Event* Event::createNewHealLocationEvent(QString map_name)
|
|||
Event* Event::createNewTriggerEvent(Project *project)
|
||||
{
|
||||
Event *event = new Event;
|
||||
event->put("event_group_type", "coord_event_group");
|
||||
event->put("event_type", EventType::Trigger);
|
||||
event->put("script_label", "NULL");
|
||||
event->put("script_var", project->varNames.first());
|
||||
event->put("script_var_value", "0");
|
||||
|
@ -127,8 +148,6 @@ Event* Event::createNewTriggerEvent(Project *project)
|
|||
Event* Event::createNewWeatherTriggerEvent(Project *project)
|
||||
{
|
||||
Event *event = new Event;
|
||||
event->put("event_group_type", "coord_event_group");
|
||||
event->put("event_type", EventType::WeatherTrigger);
|
||||
event->put("weather", project->coordEventWeatherNames.first());
|
||||
event->put("elevation", 0);
|
||||
return event;
|
||||
|
@ -137,8 +156,6 @@ Event* Event::createNewWeatherTriggerEvent(Project *project)
|
|||
Event* Event::createNewSignEvent(Project *project)
|
||||
{
|
||||
Event *event = new Event;
|
||||
event->put("event_group_type", "bg_event_group");
|
||||
event->put("event_type", EventType::Sign);
|
||||
event->put("player_facing_direction", project->bgEventFacingDirections.first());
|
||||
event->put("script_label", "NULL");
|
||||
event->put("elevation", 0);
|
||||
|
@ -148,8 +165,6 @@ Event* Event::createNewSignEvent(Project *project)
|
|||
Event* Event::createNewHiddenItemEvent(Project *project)
|
||||
{
|
||||
Event *event = new Event;
|
||||
event->put("event_group_type", "bg_event_group");
|
||||
event->put("event_type", EventType::HiddenItem);
|
||||
event->put("item", project->itemNames.first());
|
||||
event->put("flag", project->flagNames.first());
|
||||
event->put("elevation", 3);
|
||||
|
@ -165,8 +180,6 @@ Event* Event::createNewHiddenItemEvent(Project *project)
|
|||
Event* Event::createNewSecretBaseEvent(Project *project)
|
||||
{
|
||||
Event *event = new Event;
|
||||
event->put("event_group_type", "bg_event_group");
|
||||
event->put("event_type", EventType::SecretBase);
|
||||
event->put("secret_base_id", project->secretBaseIds.first());
|
||||
event->put("elevation", 0);
|
||||
return event;
|
||||
|
@ -182,81 +195,76 @@ int Event::getPixelY()
|
|||
return (this->y() * 16) - qMax(0, this->spriteHeight - 16);
|
||||
}
|
||||
|
||||
static QMap<QString, bool> expectedObjectFields {
|
||||
{"graphics_id", true},
|
||||
{"x", true},
|
||||
{"y", true},
|
||||
{"elevation", true},
|
||||
{"movement_type", true},
|
||||
{"movement_range_x", true},
|
||||
{"movement_range_y", true},
|
||||
{"trainer_type", true},
|
||||
{"trainer_sight_or_berry_tree_id", true},
|
||||
{"script", true},
|
||||
{"flag", true},
|
||||
const QSet<QString> expectedObjectFields = {
|
||||
"graphics_id",
|
||||
"elevation",
|
||||
"movement_type",
|
||||
"movement_range_x",
|
||||
"movement_range_y",
|
||||
"trainer_type",
|
||||
"trainer_sight_or_berry_tree_id",
|
||||
"script",
|
||||
"flag",
|
||||
};
|
||||
|
||||
static QMap<QString, bool> expectedWarpFields {
|
||||
{"x", true},
|
||||
{"y", true},
|
||||
{"elevation", true},
|
||||
{"dest_map", true},
|
||||
{"dest_warp_id", true},
|
||||
const QSet<QString> expectedCloneObjectFields = {
|
||||
"type",
|
||||
"graphics_id",
|
||||
"target_local_id",
|
||||
"target_map",
|
||||
};
|
||||
|
||||
static QMap<QString, bool> expectedTriggerFields {
|
||||
{"type", true},
|
||||
{"x", true},
|
||||
{"y", true},
|
||||
{"elevation", true},
|
||||
{"var", true},
|
||||
{"var_value", true},
|
||||
{"script", true},
|
||||
const QSet<QString> expectedWarpFields = {
|
||||
"elevation",
|
||||
"dest_map",
|
||||
"dest_warp_id",
|
||||
};
|
||||
|
||||
static QMap<QString, bool> expectedWeatherTriggerFields {
|
||||
{"type", true},
|
||||
{"x", true},
|
||||
{"y", true},
|
||||
{"elevation", true},
|
||||
{"weather", true},
|
||||
const QSet<QString> expectedTriggerFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"var",
|
||||
"var_value",
|
||||
"script",
|
||||
};
|
||||
|
||||
static QMap<QString, bool> expectedSignFields {
|
||||
{"type", true},
|
||||
{"x", true},
|
||||
{"y", true},
|
||||
{"elevation", true},
|
||||
{"player_facing_dir", true},
|
||||
{"script", true},
|
||||
const QSet<QString> expectedWeatherTriggerFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"weather",
|
||||
};
|
||||
|
||||
static QMap<QString, bool> expectedHiddenItemFields {
|
||||
{"type", true},
|
||||
{"x", true},
|
||||
{"y", true},
|
||||
{"elevation", true},
|
||||
{"item", true},
|
||||
{"flag", true},
|
||||
const QSet<QString> expectedSignFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"player_facing_dir",
|
||||
"script",
|
||||
};
|
||||
|
||||
static QMap<QString, bool> expectedSecretBaseFields {
|
||||
{"type", true},
|
||||
{"x", true},
|
||||
{"y", true},
|
||||
{"elevation", true},
|
||||
{"secret_base_id", true},
|
||||
const QSet<QString> expectedHiddenItemFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"item",
|
||||
"flag",
|
||||
};
|
||||
|
||||
QMap<QString, bool> Event::getExpectedFields()
|
||||
const QSet<QString> expectedSecretBaseFields = {
|
||||
"type",
|
||||
"elevation",
|
||||
"secret_base_id",
|
||||
};
|
||||
|
||||
QSet<QString> Event::getExpectedFields()
|
||||
{
|
||||
QString type = this->get("event_type");
|
||||
QMap<QString, bool> expectedFields = QMap<QString, bool>();
|
||||
QSet<QString> expectedFields = QSet<QString>();
|
||||
if (type == EventType::Object) {
|
||||
expectedFields = expectedObjectFields;
|
||||
if (projectConfig.getObjectEventInConnectionEnabled()) {
|
||||
expectedFields.insert("in_connection", true);
|
||||
if (projectConfig.getEventCloneObjectEnabled()) {
|
||||
expectedFields.insert("type");
|
||||
}
|
||||
} else if (type == EventType::CloneObject) {
|
||||
expectedFields = expectedCloneObjectFields;
|
||||
} else if (type == EventType::Warp) {
|
||||
expectedFields = expectedWarpFields;
|
||||
} else if (type == EventType::Trigger) {
|
||||
|
@ -268,23 +276,24 @@ QMap<QString, bool> Event::getExpectedFields()
|
|||
} else if (type == EventType::HiddenItem) {
|
||||
expectedFields = expectedHiddenItemFields;
|
||||
if (projectConfig.getHiddenItemQuantityEnabled()) {
|
||||
expectedFields.insert("quantity", true);
|
||||
expectedFields.insert("quantity");
|
||||
}
|
||||
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
|
||||
expectedFields.insert("underfoot", true);
|
||||
expectedFields.insert("underfoot");
|
||||
}
|
||||
} else if (type == EventType::SecretBase) {
|
||||
expectedFields = expectedSecretBaseFields;
|
||||
}
|
||||
expectedFields << "x" << "y";
|
||||
return expectedFields;
|
||||
};
|
||||
|
||||
void Event::readCustomValues(QJsonObject values)
|
||||
{
|
||||
this->customValues.clear();
|
||||
QMap<QString, bool> expectedValues = this->getExpectedFields();
|
||||
QSet<QString> expectedFields = this->getExpectedFields();
|
||||
for (QString key : values.keys()) {
|
||||
if (!expectedValues.contains(key)) {
|
||||
if (!expectedFields.contains(key)) {
|
||||
this->customValues[key] = values[key].toString();
|
||||
}
|
||||
}
|
||||
|
@ -301,24 +310,38 @@ void Event::addCustomValuesTo(OrderedJson::object *obj)
|
|||
|
||||
OrderedJson::object Event::buildObjectEventJSON()
|
||||
{
|
||||
OrderedJson::object eventObj;
|
||||
eventObj["graphics_id"] = this->get("sprite");
|
||||
if (projectConfig.getObjectEventInConnectionEnabled()) {
|
||||
eventObj["in_connection"] = this->getInt("in_connection") > 0 || this->get("in_connection") == "TRUE";
|
||||
OrderedJson::object objectObj;
|
||||
if (projectConfig.getEventCloneObjectEnabled()) {
|
||||
objectObj["type"] = "object";
|
||||
}
|
||||
eventObj["x"] = this->getS16("x");
|
||||
eventObj["y"] = this->getS16("y");
|
||||
eventObj["elevation"] = this->getInt("elevation");
|
||||
eventObj["movement_type"] = this->get("movement_type");
|
||||
eventObj["movement_range_x"] = this->getInt("radius_x");
|
||||
eventObj["movement_range_y"] = this->getInt("radius_y");
|
||||
eventObj["trainer_type"] = this->get("trainer_type");
|
||||
eventObj["trainer_sight_or_berry_tree_id"] = this->get("sight_radius_tree_id");
|
||||
eventObj["script"] = this->get("script_label");
|
||||
eventObj["flag"] = this->get("event_flag");
|
||||
this->addCustomValuesTo(&eventObj);
|
||||
objectObj["graphics_id"] = this->get("sprite");
|
||||
objectObj["x"] = this->getS16("x");
|
||||
objectObj["y"] = this->getS16("y");
|
||||
objectObj["elevation"] = this->getInt("elevation");
|
||||
objectObj["movement_type"] = this->get("movement_type");
|
||||
objectObj["movement_range_x"] = this->getInt("radius_x");
|
||||
objectObj["movement_range_y"] = this->getInt("radius_y");
|
||||
objectObj["trainer_type"] = this->get("trainer_type");
|
||||
objectObj["trainer_sight_or_berry_tree_id"] = this->get("sight_radius_tree_id");
|
||||
objectObj["script"] = this->get("script_label");
|
||||
objectObj["flag"] = this->get("event_flag");
|
||||
this->addCustomValuesTo(&objectObj);
|
||||
|
||||
return eventObj;
|
||||
return objectObj;
|
||||
}
|
||||
|
||||
OrderedJson::object Event::buildCloneObjectEventJSON(const QMap<QString, QString> &mapNamesToMapConstants)
|
||||
{
|
||||
OrderedJson::object cloneObj;
|
||||
cloneObj["type"] = "clone";
|
||||
cloneObj["graphics_id"] = this->get("sprite");
|
||||
cloneObj["x"] = this->getS16("x");
|
||||
cloneObj["y"] = this->getS16("y");
|
||||
cloneObj["target_local_id"] = this->getInt("target_local_id");
|
||||
cloneObj["target_map"] = mapNamesToMapConstants.value(this->get("target_map"));
|
||||
this->addCustomValuesTo(&cloneObj);
|
||||
|
||||
return cloneObj;
|
||||
}
|
||||
|
||||
OrderedJson::object Event::buildWarpEventJSON(const QMap<QString, QString> &mapNamesToMapConstants)
|
||||
|
@ -442,3 +465,16 @@ void Event::setFrameFromMovement(QString facingDir) {
|
|||
this->hFlip = true;
|
||||
}
|
||||
}
|
||||
|
||||
// All event groups excepts warps have IDs that start at 1
|
||||
int Event::getIndexOffset(QString group_type) {
|
||||
return (group_type == EventGroup::Warp) ? 0 : 1;
|
||||
}
|
||||
|
||||
bool Event::isValidType(QString event_type) {
|
||||
return EventTypeTable.contains(event_type);
|
||||
}
|
||||
|
||||
QString Event::typeToGroup(QString event_type) {
|
||||
return EventTypeTable.value(event_type, QString());
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ QString ParseUtil::readTextFile(const QString &path) {
|
|||
return QString();
|
||||
}
|
||||
QTextStream in(&file);
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
in.setCodec("UTF-8");
|
||||
#endif // Qt6 defaults to UTF-8, but setCodec is renamed to setEncoding
|
||||
QString text = "";
|
||||
while (!in.atEnd()) {
|
||||
text += in.readLine() + '\n';
|
||||
|
|
286
src/core/regionmapeditcommands.cpp
Normal file
|
@ -0,0 +1,286 @@
|
|||
#include "regionmapeditcommands.h"
|
||||
|
||||
|
||||
|
||||
EditTilemap::EditTilemap(RegionMap *map, QByteArray oldTilemap, QByteArray newTilemap, unsigned actionId, QUndoCommand *parent)
|
||||
: QUndoCommand(parent) {
|
||||
setText("Edit Tilemap");
|
||||
|
||||
this->map = map;
|
||||
this->oldTilemap = oldTilemap;
|
||||
this->newTilemap = newTilemap;
|
||||
this->actionId = actionId;
|
||||
}
|
||||
|
||||
void EditTilemap::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (!map) return;
|
||||
|
||||
map->setTilemap(this->newTilemap);
|
||||
}
|
||||
|
||||
void EditTilemap::undo() {
|
||||
if (!map) return;
|
||||
|
||||
map->setTilemap(this->oldTilemap);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
bool EditTilemap::mergeWith(const QUndoCommand *command) {
|
||||
const EditTilemap *other = static_cast<const EditTilemap *>(command);
|
||||
|
||||
if (this->map != other->map)
|
||||
return false;
|
||||
|
||||
if (this->actionId != other->actionId)
|
||||
return false;
|
||||
|
||||
newTilemap = other->newTilemap;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
EditLayout::EditLayout(RegionMap *map, QString layer, int index, QList<LayoutSquare> oldLayout, QList<LayoutSquare> newLayout, QUndoCommand *parent)
|
||||
: QUndoCommand(parent) {
|
||||
setText("Edit Layout");
|
||||
|
||||
this->map = map;
|
||||
this->layer = layer;
|
||||
this->index = index;
|
||||
this->oldLayout = oldLayout;
|
||||
this->newLayout = newLayout;
|
||||
}
|
||||
|
||||
void EditLayout::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (!map) return;
|
||||
|
||||
map->setLayout(this->layer, this->newLayout);
|
||||
}
|
||||
|
||||
void EditLayout::undo() {
|
||||
if (!map) return;
|
||||
|
||||
map->setLayout(this->layer, this->oldLayout);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
bool EditLayout::mergeWith(const QUndoCommand *command) {
|
||||
const EditLayout *other = static_cast<const EditLayout *>(command);
|
||||
|
||||
if (this->map != other->map)
|
||||
return false;
|
||||
|
||||
if (this->text() != other->text())
|
||||
return false;
|
||||
|
||||
if (this->index != other->index)
|
||||
return false;
|
||||
|
||||
this->newLayout = other->newLayout;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
ResizeLayout::ResizeLayout(RegionMap *map, int oldWidth, int oldHeight, int newWidth, int newHeight,
|
||||
QMap<QString, QList<LayoutSquare>> oldLayouts, QMap<QString, QList<LayoutSquare>> newLayouts, QUndoCommand *parent)
|
||||
: QUndoCommand(parent) {
|
||||
setText("Change Layout Dimensions");
|
||||
|
||||
this->map = map;
|
||||
this->oldWidth = oldWidth;
|
||||
this->oldHeight = oldHeight;
|
||||
this->newWidth = newWidth;
|
||||
this->newHeight = newHeight;
|
||||
this->oldLayouts = oldLayouts;
|
||||
this->newLayouts = newLayouts;
|
||||
}
|
||||
|
||||
void ResizeLayout::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (!map) return;
|
||||
|
||||
map->setLayoutDimensions(newWidth, newHeight, false);
|
||||
map->setAllLayouts(this->newLayouts);
|
||||
}
|
||||
|
||||
void ResizeLayout::undo() {
|
||||
if (!map) return;
|
||||
|
||||
map->setLayoutDimensions(oldWidth, oldHeight, false);
|
||||
map->setAllLayouts(this->oldLayouts);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
bool ResizeLayout::mergeWith(const QUndoCommand *command) {
|
||||
const ResizeLayout *other = static_cast<const ResizeLayout *>(command);
|
||||
|
||||
if (this->map != other->map)
|
||||
return false;
|
||||
|
||||
// always allow consecutive dimension changes to merge
|
||||
|
||||
this->newWidth = other->newWidth;
|
||||
this->newHeight = other->newHeight;
|
||||
this->newLayouts = other->newLayouts;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
EditEntry::EditEntry(RegionMap *map, QString section, MapSectionEntry oldEntry, MapSectionEntry newEntry, QUndoCommand *parent)
|
||||
: QUndoCommand(parent) {
|
||||
setText("Change Entry for " + section);
|
||||
|
||||
this->map = map;
|
||||
this->section = section;
|
||||
this->oldEntry = oldEntry;
|
||||
this->newEntry = newEntry;
|
||||
}
|
||||
|
||||
void EditEntry::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (!map) return;
|
||||
|
||||
map->setEntry(section, newEntry);
|
||||
}
|
||||
|
||||
void EditEntry::undo() {
|
||||
if (!map) return;
|
||||
|
||||
map->setEntry(section, oldEntry);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
bool EditEntry::mergeWith(const QUndoCommand *command) {
|
||||
const EditEntry *other = static_cast<const EditEntry *>(command);
|
||||
|
||||
if (this->map != other->map)
|
||||
return false;
|
||||
|
||||
if (this->section != other->section)
|
||||
return false;
|
||||
|
||||
this->newEntry = other->newEntry;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
AddEntry::AddEntry(RegionMap *map, QString section, MapSectionEntry oldEntry, MapSectionEntry newEntry, QUndoCommand *parent)
|
||||
: EditEntry(map, section, oldEntry, newEntry, parent) {
|
||||
setText("Add Entry for " + section);
|
||||
}
|
||||
|
||||
void AddEntry::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (!map) return;
|
||||
|
||||
map->setEntry(section, newEntry);
|
||||
}
|
||||
|
||||
void AddEntry::undo() {
|
||||
if (!map) return;
|
||||
|
||||
map->removeEntry(section);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
RemoveEntry::RemoveEntry(RegionMap *map, QString section, MapSectionEntry oldEntry, MapSectionEntry newEntry, QUndoCommand *parent)
|
||||
: EditEntry(map, section, oldEntry, newEntry, parent) {
|
||||
setText("Remove Entry for " + section);
|
||||
}
|
||||
|
||||
void RemoveEntry::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (!map) return;
|
||||
|
||||
map->removeEntry(section);
|
||||
}
|
||||
|
||||
void RemoveEntry::undo() {
|
||||
if (!map) return;
|
||||
|
||||
map->setEntry(section, oldEntry);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
ResizeTilemap::ResizeTilemap(RegionMap *map, QByteArray oldTilemap, QByteArray newTilemap,
|
||||
int oldWidth, int oldHeight, int newWidth, int newHeight, QUndoCommand *parent)
|
||||
: EditTilemap(map, oldTilemap, newTilemap, -1, parent) {
|
||||
setText("Resize Tilemap");
|
||||
|
||||
this->oldWidth = oldWidth;
|
||||
this->oldHeight = oldHeight;
|
||||
this->newWidth = newWidth;
|
||||
this->newHeight = newHeight;
|
||||
}
|
||||
|
||||
void ResizeTilemap::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (!map) return;
|
||||
|
||||
map->resizeTilemap(this->newWidth, this->newHeight, false);
|
||||
map->setTilemap(this->newTilemap);
|
||||
map->emitDisplay();
|
||||
}
|
||||
|
||||
void ResizeTilemap::undo() {
|
||||
if (!map) return;
|
||||
|
||||
map->resizeTilemap(this->oldWidth, this->oldHeight, false);
|
||||
map->setTilemap(this->oldTilemap);
|
||||
map->emitDisplay();
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
ClearEntries::ClearEntries(RegionMap *map, tsl::ordered_map<QString, MapSectionEntry> entries, QUndoCommand *parent) {
|
||||
setText("Clear Entries");
|
||||
|
||||
this->map = map;
|
||||
this->entries = entries;
|
||||
}
|
||||
|
||||
void ClearEntries::redo() {
|
||||
QUndoCommand::redo();
|
||||
|
||||
if (!map) return;
|
||||
|
||||
map->clearEntries();
|
||||
}
|
||||
|
||||
void ClearEntries::undo() {
|
||||
if (!map) return;
|
||||
|
||||
map->setEntries(entries);
|
||||
|
||||
QUndoCommand::undo();
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ bool Tileset::appendToMetatiles(QString metatileFile, QString friendlyName, bool
|
|||
dataString.append(QString("\t.incbin \"data/tilesets/%1/%2/metatiles.bin\"\n").arg(primaryString, friendlyName.toLower()));
|
||||
dataString.append(QString("\n\t.align 1\n"));
|
||||
dataString.append(QString("gMetatileAttributes_%1::\n").arg(friendlyName));
|
||||
dataString.append(QString("\t.incbin \"data/tilesets/%1/%2/metatile_attributes.bin\"").arg(primaryString, friendlyName.toLower()));
|
||||
dataString.append(QString("\t.incbin \"data/tilesets/%1/%2/metatile_attributes.bin\"\n").arg(primaryString, friendlyName.toLower()));
|
||||
file.write(dataString.toUtf8());
|
||||
file.flush();
|
||||
file.close();
|
||||
|
|
|
@ -2064,8 +2064,8 @@ DraggablePixmapItem* Editor::addNewEvent(QString event_type) {
|
|||
bool Editor::eventLimitReached(Map *map, QString event_type)
|
||||
{
|
||||
if (project && map && !event_type.isEmpty()) {
|
||||
if (event_type == EventType::Object)
|
||||
return map->events.value("object_event_group").length() >= project->getMaxObjectEvents();
|
||||
if (Event::typeToGroup(event_type) == EventGroup::Object)
|
||||
return map->events.value(EventGroup::Object).length() >= project->getMaxObjectEvents();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -349,12 +349,15 @@ void MainWindow::markMapEdited() {
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::setWildEncountersUIEnabled(bool enabled) {
|
||||
ui->actionUse_Encounter_Json->setChecked(enabled);
|
||||
ui->mainTabBar->setTabEnabled(4, enabled);
|
||||
}
|
||||
|
||||
void MainWindow::setProjectSpecificUIVisibility()
|
||||
{
|
||||
ui->actionUse_Encounter_Json->setChecked(projectConfig.getEncounterJsonActive());
|
||||
ui->actionUse_Poryscript->setChecked(projectConfig.getUsePoryScript());
|
||||
|
||||
ui->mainTabBar->setTabEnabled(4, projectConfig.getEncounterJsonActive());
|
||||
this->setWildEncountersUIEnabled(projectConfig.getEncounterJsonActive());
|
||||
|
||||
switch (projectConfig.getBaseGameVersion())
|
||||
{
|
||||
|
@ -385,27 +388,17 @@ void MainWindow::setProjectSpecificUIVisibility()
|
|||
ui->label_AllowEscapeRope->setVisible(true);
|
||||
// TODO: pokefirered is not set up for the Region Map Editor and vice versa.
|
||||
// porymap will crash on attempt. Remove below once resolved
|
||||
ui->actionRegion_Map_Editor->setVisible(false);
|
||||
ui->actionRegion_Map_Editor->setVisible(true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (projectConfig.getEventWeatherTriggerEnabled()) {
|
||||
ui->newEventToolButton->newWeatherTriggerAction->setVisible(true);
|
||||
} else {
|
||||
ui->newEventToolButton->newWeatherTriggerAction->setVisible(false);
|
||||
}
|
||||
if (projectConfig.getEventSecretBaseEnabled()) {
|
||||
ui->newEventToolButton->newSecretBaseAction->setVisible(true);
|
||||
} else {
|
||||
ui->newEventToolButton->newSecretBaseAction->setVisible(false);
|
||||
}
|
||||
if (projectConfig.getFloorNumberEnabled()) {
|
||||
ui->spinBox_FloorNumber->setVisible(true);
|
||||
ui->label_FloorNumber->setVisible(true);
|
||||
} else {
|
||||
ui->spinBox_FloorNumber->setVisible(false);
|
||||
ui->label_FloorNumber->setVisible(false);
|
||||
}
|
||||
ui->newEventToolButton->newWeatherTriggerAction->setVisible(projectConfig.getEventWeatherTriggerEnabled());
|
||||
ui->newEventToolButton->newSecretBaseAction->setVisible(projectConfig.getEventSecretBaseEnabled());
|
||||
ui->newEventToolButton->newCloneObjectAction->setVisible(projectConfig.getEventCloneObjectEnabled());
|
||||
|
||||
bool floorNumEnabled = projectConfig.getFloorNumberEnabled();
|
||||
ui->spinBox_FloorNumber->setVisible(floorNumEnabled);
|
||||
ui->label_FloorNumber->setVisible(floorNumEnabled);
|
||||
}
|
||||
|
||||
void MainWindow::mapSortOrder_changed(QAction *action)
|
||||
|
@ -525,6 +518,7 @@ bool MainWindow::openProject(QString dir) {
|
|||
editor->project = new Project(this);
|
||||
QObject::connect(editor->project, &Project::reloadProject, this, &MainWindow::on_action_Reload_Project_triggered);
|
||||
QObject::connect(editor->project, &Project::mapCacheCleared, this, &MainWindow::onMapCacheCleared);
|
||||
QObject::connect(editor->project, &Project::disableWildEncountersUI, [this]() { this->setWildEncountersUIEnabled(false); });
|
||||
QObject::connect(editor->project, &Project::uncheckMonitorFilesAction, [this]() { ui->actionMonitor_Project_Files->setChecked(false); });
|
||||
on_actionMonitor_Project_Files_triggered(porymapConfig.getMonitorFiles());
|
||||
editor->project->set_root(dir);
|
||||
|
@ -702,22 +696,22 @@ void MainWindow::refreshMapScene()
|
|||
on_horizontalSlider_MetatileZoom_valueChanged(ui->horizontalSlider_MetatileZoom->value());
|
||||
}
|
||||
|
||||
void MainWindow::openWarpMap(QString map_name, QString warp_num) {
|
||||
void MainWindow::openWarpMap(QString map_name, QString event_id, QString event_group) {
|
||||
// Ensure valid destination map name.
|
||||
if (!editor->project->mapNames.contains(map_name)) {
|
||||
logError(QString("Invalid warp destination map name '%1'").arg(map_name));
|
||||
logError(QString("Invalid map name '%1'").arg(map_name));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure valid destination warp number.
|
||||
// Ensure valid event number.
|
||||
bool ok;
|
||||
int warpNum = warp_num.toInt(&ok, 0);
|
||||
int event_index = event_id.toInt(&ok, 0);
|
||||
if (!ok) {
|
||||
logError(QString("Invalid warp number '%1' for destination map '%2'").arg(warp_num).arg(map_name));
|
||||
logError(QString("Invalid event number '%1' for map '%2'").arg(event_id).arg(map_name));
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the destination map, and select the target warp event.
|
||||
// Open the destination map.
|
||||
if (!setMap(map_name, true)) {
|
||||
QMessageBox msgBox(this);
|
||||
QString errorMsg = QString("There was an error opening map %1. Please see %2 for full error details.\n\n%3")
|
||||
|
@ -728,11 +722,13 @@ void MainWindow::openWarpMap(QString map_name, QString warp_num) {
|
|||
return;
|
||||
}
|
||||
|
||||
QList<Event*> warp_events = editor->map->events["warp_event_group"];
|
||||
if (warp_events.length() > warpNum) {
|
||||
Event *warp_event = warp_events.at(warpNum);
|
||||
// Select the target event.
|
||||
event_index -= Event::getIndexOffset(event_group);
|
||||
QList<Event*> events = editor->map->events[event_group];
|
||||
if (event_index < events.length() && event_index >= 0) {
|
||||
Event *event = events.at(event_index);
|
||||
for (DraggablePixmapItem *item : editor->getObjects()) {
|
||||
if (item->event == warp_event) {
|
||||
if (item->event == event) {
|
||||
editor->selected_events->clear();
|
||||
editor->selected_events->append(item);
|
||||
editor->updateSelectedEvents();
|
||||
|
@ -1170,11 +1166,11 @@ void MainWindow::onAddNewMapToLayoutClick(QAction* triggeredAction)
|
|||
}
|
||||
|
||||
void MainWindow::onNewMapCreated() {
|
||||
QString newMapName = this->newmapprompt->map->name;
|
||||
int newMapGroup = this->newmapprompt->group;
|
||||
Map *newMap = this->newmapprompt->map;
|
||||
bool existingLayout = this->newmapprompt->existingLayout;
|
||||
bool importedMap = this->newmapprompt->importedMap;
|
||||
QString newMapName = this->newMapPrompt->map->name;
|
||||
int newMapGroup = this->newMapPrompt->group;
|
||||
Map *newMap = this->newMapPrompt->map;
|
||||
bool existingLayout = this->newMapPrompt->existingLayout;
|
||||
bool importedMap = this->newMapPrompt->importedMap;
|
||||
|
||||
newMap = editor->project->addNewMapToGroup(newMapName, newMapGroup, newMap, existingLayout, importedMap);
|
||||
|
||||
|
@ -1199,52 +1195,52 @@ void MainWindow::onNewMapCreated() {
|
|||
editor->save();// required
|
||||
}
|
||||
|
||||
disconnect(this->newmapprompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
|
||||
disconnect(this->newMapPrompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
|
||||
delete newMap;
|
||||
}
|
||||
|
||||
void MainWindow::openNewMapPopupWindow(int type, QVariant data) {
|
||||
if (!this->newmapprompt) {
|
||||
this->newmapprompt = new NewMapPopup(this, this->editor->project);
|
||||
if (!this->newMapPrompt) {
|
||||
this->newMapPrompt = new NewMapPopup(this, this->editor->project);
|
||||
}
|
||||
if (!this->newmapprompt->isVisible()) {
|
||||
this->newmapprompt->show();
|
||||
if (!this->newMapPrompt->isVisible()) {
|
||||
this->newMapPrompt->show();
|
||||
} else {
|
||||
this->newmapprompt->raise();
|
||||
this->newmapprompt->activateWindow();
|
||||
this->newMapPrompt->raise();
|
||||
this->newMapPrompt->activateWindow();
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case MapSortOrder::Group:
|
||||
this->newmapprompt->init(type, data.toInt(), QString(), QString());
|
||||
this->newMapPrompt->init(type, data.toInt(), QString(), QString());
|
||||
break;
|
||||
case MapSortOrder::Area:
|
||||
this->newmapprompt->init(type, 0, data.toString(), QString());
|
||||
this->newMapPrompt->init(type, 0, data.toString(), QString());
|
||||
break;
|
||||
case MapSortOrder::Layout:
|
||||
this->newmapprompt->init(type, 0, QString(), data.toString());
|
||||
this->newMapPrompt->init(type, 0, QString(), data.toString());
|
||||
break;
|
||||
}
|
||||
connect(this->newmapprompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
|
||||
this->newmapprompt->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(this->newMapPrompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
|
||||
this->newMapPrompt->setAttribute(Qt::WA_DeleteOnClose);
|
||||
}
|
||||
|
||||
void MainWindow::openNewMapPopupWindowImportMap(MapLayout *mapLayout) {
|
||||
if (!this->newmapprompt) {
|
||||
this->newmapprompt = new NewMapPopup(this, this->editor->project);
|
||||
if (!this->newMapPrompt) {
|
||||
this->newMapPrompt = new NewMapPopup(this, this->editor->project);
|
||||
}
|
||||
if (!this->newmapprompt->isVisible()) {
|
||||
this->newmapprompt->show();
|
||||
if (!this->newMapPrompt->isVisible()) {
|
||||
this->newMapPrompt->show();
|
||||
} else {
|
||||
this->newmapprompt->raise();
|
||||
this->newmapprompt->activateWindow();
|
||||
this->newMapPrompt->raise();
|
||||
this->newMapPrompt->activateWindow();
|
||||
}
|
||||
|
||||
this->newmapprompt->initImportMap(mapLayout);
|
||||
this->newMapPrompt->initImportMap(mapLayout);
|
||||
|
||||
connect(this->newmapprompt, SIGNAL(applied()), this, SLOT(onNewMapCreated()));
|
||||
connect(this->newmapprompt, &QObject::destroyed, [=](QObject *) { this->newmapprompt = nullptr; });
|
||||
this->newmapprompt->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(this->newMapPrompt, SIGNAL(applied()), this, SLOT(onNewMapCreated()));
|
||||
connect(this->newMapPrompt, &QObject::destroyed, [=](QObject *) { this->newMapPrompt = nullptr; });
|
||||
this->newMapPrompt->setAttribute(Qt::WA_DeleteOnClose);
|
||||
}
|
||||
|
||||
void MainWindow::on_action_NewMap_triggered() {
|
||||
|
@ -1802,15 +1798,12 @@ void MainWindow::connectSubEditorsToShortcutsEditor() {
|
|||
connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
|
||||
tilesetEditor, &TilesetEditor::applyUserShortcuts);
|
||||
|
||||
// TODO: Remove this check when the region map editor supports pokefirered.
|
||||
if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokefirered) {
|
||||
if (!regionMapEditor)
|
||||
initRegionMapEditor();
|
||||
if (regionMapEditor)
|
||||
connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved,
|
||||
regionMapEditor, &RegionMapEditor::applyUserShortcuts);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionPencil_triggered()
|
||||
{
|
||||
|
@ -1859,7 +1852,7 @@ void MainWindow::addNewEvent(QString event_type)
|
|||
} else {
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setText("Failed to add new event");
|
||||
if (event_type == EventType::Object) {
|
||||
if (Event::typeToGroup(event_type) == EventGroup::Object) {
|
||||
msgBox.setInformativeText(QString("The limit for object events (%1) has been reached.\n\n"
|
||||
"This limit can be adjusted with OBJECT_EVENT_TEMPLATES_COUNT in 'include/constants/global.h'.")
|
||||
.arg(editor->project->getMaxObjectEvents()));
|
||||
|
@ -1879,57 +1872,20 @@ void MainWindow::updateObjects() {
|
|||
selectedHealspot = nullptr;
|
||||
ui->tabWidget_EventType->clear();
|
||||
|
||||
bool hasObjects = false;
|
||||
bool hasWarps = false;
|
||||
bool hasTriggers = false;
|
||||
bool hasBGs = false;
|
||||
bool hasHealspots = false;
|
||||
|
||||
for (DraggablePixmapItem *item : editor->getObjects())
|
||||
{
|
||||
QString event_type = item->event->get("event_type");
|
||||
|
||||
if (event_type == EventType::Object) {
|
||||
hasObjects = true;
|
||||
}
|
||||
else if (event_type == EventType::Warp) {
|
||||
hasWarps = true;
|
||||
}
|
||||
else if (event_type == EventType::Trigger || event_type == EventType::WeatherTrigger) {
|
||||
hasTriggers = true;
|
||||
}
|
||||
else if (event_type == EventType::Sign || event_type == EventType::HiddenItem || event_type == EventType::SecretBase) {
|
||||
hasBGs = true;
|
||||
}
|
||||
else if (event_type == EventType::HealLocation) {
|
||||
hasHealspots = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasObjects)
|
||||
{
|
||||
if (editor->map->events.value(EventGroup::Object).length())
|
||||
ui->tabWidget_EventType->addTab(eventTabObjectWidget, "Objects");
|
||||
}
|
||||
|
||||
if (hasWarps)
|
||||
{
|
||||
if (editor->map->events.value(EventGroup::Warp).length())
|
||||
ui->tabWidget_EventType->addTab(eventTabWarpWidget, "Warps");
|
||||
}
|
||||
|
||||
if (hasTriggers)
|
||||
{
|
||||
if (editor->map->events.value(EventGroup::Coord).length())
|
||||
ui->tabWidget_EventType->addTab(eventTabTriggerWidget, "Triggers");
|
||||
}
|
||||
|
||||
if (hasBGs)
|
||||
{
|
||||
if (editor->map->events.value(EventGroup::Bg).length())
|
||||
ui->tabWidget_EventType->addTab(eventTabBGWidget, "BGs");
|
||||
}
|
||||
|
||||
if (hasHealspots)
|
||||
{
|
||||
if (editor->map->events.value(EventGroup::Heal).length())
|
||||
ui->tabWidget_EventType->addTab(eventTabHealspotWidget, "Healspots");
|
||||
}
|
||||
|
||||
updateSelectedObjects();
|
||||
}
|
||||
|
@ -1956,7 +1912,6 @@ void MainWindow::updateSelectedObjects() {
|
|||
|
||||
QList<EventPropertiesFrame *> frames;
|
||||
|
||||
bool inConnectionEnabled = projectConfig.getObjectEventInConnectionEnabled();
|
||||
bool quantityEnabled = projectConfig.getHiddenItemQuantityEnabled();
|
||||
bool underfootEnabled = projectConfig.getHiddenItemRequiresItemfinderEnabled();
|
||||
bool respawnDataEnabled = projectConfig.getHealLocationRespawnDataEnabled();
|
||||
|
@ -1991,9 +1946,7 @@ void MainWindow::updateSelectedObjects() {
|
|||
QString event_type = item->event->get("event_type");
|
||||
QString event_group_type = item->event->get("event_group_type");
|
||||
QString map_name = item->event->get("map_name");
|
||||
int event_offs;
|
||||
if (event_type == EventType::Warp) { event_offs = 0; }
|
||||
else { event_offs = 1; }
|
||||
int event_offs = Event::getIndexOffset(event_group_type);
|
||||
frame->ui->label_name->setText(QString("%1 Id").arg(event_type));
|
||||
|
||||
if (events.count() == 1)
|
||||
|
@ -2021,7 +1974,6 @@ void MainWindow::updateSelectedObjects() {
|
|||
field_labels["radius_y"] = "Movement Radius Y";
|
||||
field_labels["trainer_type"] = "Trainer Type";
|
||||
field_labels["sight_radius_tree_id"] = "Sight Radius / Berry Tree ID";
|
||||
field_labels["in_connection"] = "In Connection";
|
||||
field_labels["destination_warp"] = "Destination Warp";
|
||||
field_labels["destination_map_name"] = "Destination Map";
|
||||
field_labels["script_var"] = "Var";
|
||||
|
@ -2035,13 +1987,15 @@ void MainWindow::updateSelectedObjects() {
|
|||
field_labels["secret_base_id"] = "Secret Base Id";
|
||||
field_labels["respawn_map"] = "Respawn Map";
|
||||
field_labels["respawn_npc"] = "Respawn NPC";
|
||||
field_labels["target_local_id"] = "Target Local Id";
|
||||
field_labels["target_map"] = "Target Map";
|
||||
|
||||
QStringList fields;
|
||||
|
||||
if (event_type == EventType::Object) {
|
||||
|
||||
frame->ui->sprite->setVisible(true);
|
||||
frame->ui->comboBox_sprite->addItems(editor->project->gfxNames);
|
||||
frame->ui->comboBox_sprite->addItems(editor->project->gfxDefines.keys());
|
||||
frame->ui->comboBox_sprite->setCurrentIndex(frame->ui->comboBox_sprite->findText(item->event->get("sprite")));
|
||||
connect(frame->ui->comboBox_sprite, &QComboBox::currentTextChanged, item, &DraggablePixmapItem::set_sprite);
|
||||
connect(frame->ui->comboBox_sprite, &QComboBox::currentTextChanged, this, &MainWindow::markMapEdited);
|
||||
|
@ -2063,7 +2017,17 @@ void MainWindow::updateSelectedObjects() {
|
|||
fields << "event_flag";
|
||||
fields << "trainer_type";
|
||||
fields << "sight_radius_tree_id";
|
||||
if (inConnectionEnabled) fields << "in_connection";
|
||||
}
|
||||
else if (event_type == EventType::CloneObject) {
|
||||
frame->ui->sprite->setVisible(true);
|
||||
frame->ui->comboBox_sprite->setEnabled(false);
|
||||
frame->ui->comboBox_sprite->addItem(item->event->get("sprite"));
|
||||
|
||||
frame->ui->spinBox_z->setVisible(false);
|
||||
frame->ui->label_z->setVisible(false);
|
||||
|
||||
fields << "target_local_id";
|
||||
fields << "target_map";
|
||||
}
|
||||
else if (event_type == EventType::Warp) {
|
||||
fields << "destination_map_name";
|
||||
|
@ -2101,8 +2065,8 @@ void MainWindow::updateSelectedObjects() {
|
|||
}
|
||||
|
||||
// Some keys shouldn't use a combobox
|
||||
QStringList spinKeys = {"quantity", "respawn_npc"};
|
||||
QStringList checkKeys = {"underfoot", "in_connection"};
|
||||
QStringList spinKeys = {"quantity", "respawn_npc", "target_local_id"};
|
||||
QStringList checkKeys = {"underfoot"};
|
||||
for (QString key : fields) {
|
||||
QString value = item->event->get(key);
|
||||
QWidget *widget = new QWidget(frame);
|
||||
|
@ -2226,8 +2190,6 @@ void MainWindow::updateSelectedObjects() {
|
|||
combo->setToolTip("The maximum sight range of a trainer,\n"
|
||||
"OR the unique id of the berry tree.");
|
||||
combo->setMinimumContentsLength(4);
|
||||
} else if (key == "in_connection") {
|
||||
check->setToolTip("Check if object is positioned in the connection to another map.");
|
||||
} else if (key == "respawn_map") {
|
||||
if (!editor->project->mapNames.contains(value)) {
|
||||
combo->addItem(value);
|
||||
|
@ -2239,6 +2201,27 @@ void MainWindow::updateSelectedObjects() {
|
|||
"upon respawning after whiteout.");
|
||||
spin->setMinimum(1);
|
||||
spin->setMaximum(126);
|
||||
} else if (key == "target_local_id") {
|
||||
spin->setToolTip("event_object ID of the object being cloned.");
|
||||
spin->setMinimum(1);
|
||||
spin->setMaximum(126);
|
||||
connect(spin, QOverload<int>::of(&NoScrollSpinBox::valueChanged), [item, frame](int value) {
|
||||
item->event->put("target_local_id", value);
|
||||
item->updatePixmap();
|
||||
frame->ui->comboBox_sprite->setItemText(0, item->event->get("sprite"));
|
||||
});
|
||||
} else if (key == "target_map") {
|
||||
if (!editor->project->mapNames.contains(value)) {
|
||||
combo->addItem(value);
|
||||
}
|
||||
combo->addItems(editor->project->mapNames);
|
||||
combo->setCurrentIndex(combo->findText(value));
|
||||
combo->setToolTip("The name of the map that the object being cloned is on.");
|
||||
connect(combo, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged), this, [item, frame](QString value){
|
||||
item->event->put("target_map", value);
|
||||
item->updatePixmap();
|
||||
frame->ui->comboBox_sprite->setItemText(0, item->event->get("sprite"));
|
||||
});
|
||||
} else {
|
||||
combo->addItem(value);
|
||||
}
|
||||
|
@ -2323,27 +2306,27 @@ void MainWindow::updateSelectedObjects() {
|
|||
{
|
||||
QString event_group_type = events[0]->event->get("event_group_type");
|
||||
|
||||
if (event_group_type == "object_event_group") {
|
||||
if (event_group_type == EventGroup::Object) {
|
||||
scrollTarget = ui->scrollArea_Objects;
|
||||
target = ui->scrollAreaWidgetContents_Objects;
|
||||
ui->tabWidget_EventType->setCurrentWidget(ui->tab_Objects);
|
||||
}
|
||||
else if (event_group_type == "warp_event_group") {
|
||||
else if (event_group_type == EventGroup::Warp) {
|
||||
scrollTarget = ui->scrollArea_Warps;
|
||||
target = ui->scrollAreaWidgetContents_Warps;
|
||||
ui->tabWidget_EventType->setCurrentWidget(ui->tab_Warps);
|
||||
}
|
||||
else if (event_group_type == "coord_event_group") {
|
||||
else if (event_group_type == EventGroup::Coord) {
|
||||
scrollTarget = ui->scrollArea_Triggers;
|
||||
target = ui->scrollAreaWidgetContents_Triggers;
|
||||
ui->tabWidget_EventType->setCurrentWidget(ui->tab_Triggers);
|
||||
}
|
||||
else if (event_group_type == "bg_event_group") {
|
||||
else if (event_group_type == EventGroup::Bg) {
|
||||
scrollTarget = ui->scrollArea_BGs;
|
||||
target = ui->scrollAreaWidgetContents_BGs;
|
||||
ui->tabWidget_EventType->setCurrentWidget(ui->tab_BGs);
|
||||
}
|
||||
else if (event_group_type == "heal_event_group") {
|
||||
else if (event_group_type == EventGroup::Heal) {
|
||||
scrollTarget = ui->scrollArea_Healspots;
|
||||
target = ui->scrollAreaWidgetContents_Healspots;
|
||||
ui->tabWidget_EventType->setCurrentWidget(ui->tab_Healspots);
|
||||
|
@ -2400,23 +2383,23 @@ QString MainWindow::getEventGroupFromTabWidget(QWidget *tab)
|
|||
QString ret = "";
|
||||
if (tab == eventTabObjectWidget)
|
||||
{
|
||||
ret = "object_event_group";
|
||||
ret = EventGroup::Object;
|
||||
}
|
||||
else if (tab == eventTabWarpWidget)
|
||||
{
|
||||
ret = "warp_event_group";
|
||||
ret = EventGroup::Warp;
|
||||
}
|
||||
else if (tab == eventTabTriggerWidget)
|
||||
{
|
||||
ret = "coord_event_group";
|
||||
ret = EventGroup::Coord;
|
||||
}
|
||||
else if (tab == eventTabBGWidget)
|
||||
{
|
||||
ret = "bg_event_group";
|
||||
ret = EventGroup::Bg;
|
||||
}
|
||||
else if (tab == eventTabHealspotWidget)
|
||||
{
|
||||
ret = "heal_event_group";
|
||||
ret = EventGroup::Heal;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -2426,23 +2409,23 @@ void MainWindow::eventTabChanged(int index) {
|
|||
QString group = getEventGroupFromTabWidget(ui->tabWidget_EventType->widget(index));
|
||||
DraggablePixmapItem *selectedEvent = nullptr;
|
||||
|
||||
if (group == "object_event_group") {
|
||||
if (group == EventGroup::Object) {
|
||||
selectedEvent = selectedObject;
|
||||
ui->newEventToolButton->setDefaultAction(ui->newEventToolButton->newObjectAction);
|
||||
}
|
||||
else if (group == "warp_event_group") {
|
||||
else if (group == EventGroup::Warp) {
|
||||
selectedEvent = selectedWarp;
|
||||
ui->newEventToolButton->setDefaultAction(ui->newEventToolButton->newWarpAction);
|
||||
}
|
||||
else if (group == "coord_event_group") {
|
||||
else if (group == EventGroup::Coord) {
|
||||
selectedEvent = selectedTrigger;
|
||||
ui->newEventToolButton->setDefaultAction(ui->newEventToolButton->newTriggerAction);
|
||||
}
|
||||
else if (group == "bg_event_group") {
|
||||
else if (group == EventGroup::Bg) {
|
||||
selectedEvent = selectedBG;
|
||||
ui->newEventToolButton->setDefaultAction(ui->newEventToolButton->newSignAction);
|
||||
}
|
||||
else if (group == "heal_event_group") {
|
||||
else if (group == EventGroup::Heal) {
|
||||
selectedEvent = selectedHealspot;
|
||||
}
|
||||
|
||||
|
@ -2468,7 +2451,7 @@ void MainWindow::eventTabChanged(int index) {
|
|||
void MainWindow::selectedEventIndexChanged(int index)
|
||||
{
|
||||
QString group = getEventGroupFromTabWidget(ui->tabWidget_EventType->currentWidget());
|
||||
int event_offs = group == "warp_event_group" ? 0 : 1;
|
||||
int event_offs = Event::getIndexOffset(group);
|
||||
Event *event = editor->map->events.value(group).at(index - event_offs);
|
||||
DraggablePixmapItem *selectedEvent = nullptr;
|
||||
for (QGraphicsItem *child : editor->events_group->childItems()) {
|
||||
|
@ -2502,7 +2485,7 @@ void MainWindow::on_toolButton_deleteObject_clicked() {
|
|||
int numDeleted = 0;
|
||||
for (DraggablePixmapItem *item : *editor->selected_events) {
|
||||
QString event_group = item->event->get("event_group_type");
|
||||
if (event_group != "heal_event_group") {
|
||||
if (event_group != EventGroup::Heal) {
|
||||
// Get the index for the event that should be selected after this event has been deleted.
|
||||
// If it's at the end of the list, select the previous event, otherwise select the next one.
|
||||
// Don't bother getting the event to select if there are still more events to delete
|
||||
|
@ -3164,8 +3147,12 @@ void MainWindow::on_actionRegion_Map_Editor_triggered() {
|
|||
|
||||
bool MainWindow::initRegionMapEditor() {
|
||||
this->regionMapEditor = new RegionMapEditor(this, this->editor->project);
|
||||
bool success = this->regionMapEditor->loadRegionMapData()
|
||||
&& this->regionMapEditor->loadCityMaps();
|
||||
this->regionMapEditor->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(this->regionMapEditor, &QObject::destroyed, [this](){
|
||||
this->regionMapEditor = nullptr;
|
||||
});
|
||||
|
||||
bool success = this->regionMapEditor->load();
|
||||
if (!success) {
|
||||
delete this->regionMapEditor;
|
||||
this->regionMapEditor = nullptr;
|
||||
|
@ -3182,16 +3169,26 @@ bool MainWindow::initRegionMapEditor() {
|
|||
}
|
||||
|
||||
void MainWindow::closeSupplementaryWindows() {
|
||||
if (this->tilesetEditor)
|
||||
if (this->tilesetEditor) {
|
||||
delete this->tilesetEditor;
|
||||
if (this->regionMapEditor)
|
||||
this->tilesetEditor = nullptr;
|
||||
}
|
||||
if (this->regionMapEditor) {
|
||||
delete this->regionMapEditor;
|
||||
if (this->mapImageExporter)
|
||||
this->regionMapEditor = nullptr;
|
||||
}
|
||||
if (this->mapImageExporter) {
|
||||
delete this->mapImageExporter;
|
||||
if (this->newmapprompt)
|
||||
delete this->newmapprompt;
|
||||
if (this->shortcutsEditor)
|
||||
this->mapImageExporter = nullptr;
|
||||
}
|
||||
if (this->newMapPrompt) {
|
||||
delete this->newMapPrompt;
|
||||
this->newMapPrompt = nullptr;
|
||||
}
|
||||
if (this->shortcutsEditor) {
|
||||
delete this->shortcutsEditor;
|
||||
this->shortcutsEditor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event) {
|
||||
|
|
|
@ -833,7 +833,7 @@ void MainWindow::saveMetatileAttributesByMetatileId(int metatileId) {
|
|||
this->editor->project->saveTilesetMetatileAttributes(tileset);
|
||||
|
||||
// If the Tileset Editor is currently displaying the updated metatile, refresh it
|
||||
if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatile() == metatileId)
|
||||
if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatileId() == metatileId)
|
||||
this->tilesetEditor->updateTilesets(this->editor->map->layout->tileset_primary_label, this->editor->map->layout->tileset_secondary_label);
|
||||
}
|
||||
|
||||
|
@ -863,7 +863,7 @@ void MainWindow::setMetatileLabel(int metatileId, QString label) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatile() == metatileId) {
|
||||
if (this->tilesetEditor && this->tilesetEditor->getSelectedMetatileId() == metatileId) {
|
||||
this->tilesetEditor->setMetatileLabel(label);
|
||||
} else if (metatile->label != label) {
|
||||
metatile->label = label;
|
||||
|
|
174
src/project.cpp
|
@ -211,16 +211,17 @@ bool Project::loadMapData(Map* map) {
|
|||
map->sharedScriptsMap = mapObj["shared_scripts_map"].toString();
|
||||
|
||||
// Events
|
||||
map->events["object_event_group"].clear();
|
||||
map->events[EventGroup::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 ? event["type"].toString() : "object";
|
||||
if (type.isEmpty() || type == "object") {
|
||||
Event *object = new Event(event, EventType::Object);
|
||||
object->put("map_name", map->name);
|
||||
object->put("sprite", event["graphics_id"].toString());
|
||||
if (projectConfig.getObjectEventInConnectionEnabled()) {
|
||||
object->put("in_connection", event["in_connection"].toBool());
|
||||
}
|
||||
object->put("x", QString::number(event["x"].toInt()));
|
||||
object->put("y", QString::number(event["y"].toInt()));
|
||||
object->put("elevation", QString::number(event["elevation"].toInt()));
|
||||
|
@ -231,11 +232,35 @@ bool Project::loadMapData(Map* map) {
|
|||
object->put("sight_radius_tree_id", event["trainer_sight_or_berry_tree_id"].toString());
|
||||
object->put("script_label", event["script"].toString());
|
||||
object->put("event_flag", event["flag"].toString());
|
||||
object->put("event_group_type", "object_event_group");
|
||||
map->events["object_event_group"].append(object);
|
||||
object->put("event_group_type", EventGroup::Object);
|
||||
map->events[EventGroup::Object].append(object);
|
||||
} else if (type == "clone") {
|
||||
Event *object = new Event(event, EventType::CloneObject);
|
||||
object->put("map_name", map->name);
|
||||
object->put("sprite", event["graphics_id"].toString());
|
||||
object->put("x", QString::number(event["x"].toInt()));
|
||||
object->put("y", QString::number(event["y"].toInt()));
|
||||
object->put("target_local_id", QString::number(event["target_local_id"].toInt()));
|
||||
|
||||
// Ensure the target map constant is valid before adding it to the events.
|
||||
QString mapConstant = event["target_map"].toString();
|
||||
if (mapConstantsToMapNames.contains(mapConstant)) {
|
||||
object->put("target_map", mapConstantsToMapNames.value(mapConstant));
|
||||
object->put("event_group_type", EventGroup::Object);
|
||||
map->events[EventGroup::Object].append(object);
|
||||
} else if (mapConstant == NONE_MAP_CONSTANT) {
|
||||
object->put("target_map", NONE_MAP_NAME);
|
||||
object->put("event_group_type", EventGroup::Object);
|
||||
map->events[EventGroup::Object].append(object);
|
||||
} else {
|
||||
logError(QString("Destination map constant '%1' is invalid").arg(mapConstant));
|
||||
}
|
||||
} else {
|
||||
logError(QString("Map %1 object_event %2 has invalid type '%3'. Must be 'object' or 'clone'.").arg(map->name).arg(i).arg(type));
|
||||
}
|
||||
}
|
||||
|
||||
map->events["warp_event_group"].clear();
|
||||
map->events[EventGroup::Warp].clear();
|
||||
QJsonArray warpEventsArr = mapObj["warp_events"].toArray();
|
||||
for (int i = 0; i < warpEventsArr.size(); i++) {
|
||||
QJsonObject event = warpEventsArr[i].toObject();
|
||||
|
@ -250,18 +275,18 @@ bool Project::loadMapData(Map* map) {
|
|||
QString mapConstant = event["dest_map"].toString();
|
||||
if (mapConstantsToMapNames.contains(mapConstant)) {
|
||||
warp->put("destination_map_name", mapConstantsToMapNames.value(mapConstant));
|
||||
warp->put("event_group_type", "warp_event_group");
|
||||
map->events["warp_event_group"].append(warp);
|
||||
warp->put("event_group_type", EventGroup::Warp);
|
||||
map->events[EventGroup::Warp].append(warp);
|
||||
} else if (mapConstant == NONE_MAP_CONSTANT) {
|
||||
warp->put("destination_map_name", NONE_MAP_NAME);
|
||||
warp->put("event_group_type", "warp_event_group");
|
||||
map->events["warp_event_group"].append(warp);
|
||||
warp->put("event_group_type", EventGroup::Warp);
|
||||
map->events[EventGroup::Warp].append(warp);
|
||||
} else {
|
||||
logError(QString("Destination map constant '%1' is invalid for warp").arg(mapConstant));
|
||||
}
|
||||
}
|
||||
|
||||
map->events["heal_event_group"].clear();
|
||||
map->events[EventGroup::Heal].clear();
|
||||
for (auto it = healLocations.begin(); it != healLocations.end(); it++) {
|
||||
|
||||
HealLocation loc = *it;
|
||||
|
@ -277,18 +302,18 @@ bool Project::loadMapData(Map* map) {
|
|||
heal->put("index", loc.index);
|
||||
heal->put("elevation", 3); // TODO: change this?
|
||||
heal->put("destination_map_name", mapConstantsToMapNames.value(map->name));
|
||||
heal->put("event_group_type", "heal_event_group");
|
||||
heal->put("event_group_type", EventGroup::Heal);
|
||||
heal->put("event_type", EventType::HealLocation);
|
||||
if (projectConfig.getHealLocationRespawnDataEnabled()) {
|
||||
heal->put("respawn_map", mapConstantsToMapNames.value(QString("MAP_" + loc.respawnMap)));
|
||||
heal->put("respawn_npc", loc.respawnNPC);
|
||||
}
|
||||
map->events["heal_event_group"].append(heal);
|
||||
map->events[EventGroup::Heal].append(heal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
map->events["coord_event_group"].clear();
|
||||
map->events[EventGroup::Coord].clear();
|
||||
QJsonArray coordEventsArr = mapObj["coord_events"].toArray();
|
||||
for (int i = 0; i < coordEventsArr.size(); i++) {
|
||||
QJsonObject event = coordEventsArr[i].toObject();
|
||||
|
@ -302,8 +327,8 @@ bool Project::loadMapData(Map* map) {
|
|||
coord->put("script_var", event["var"].toString());
|
||||
coord->put("script_var_value", event["var_value"].toString());
|
||||
coord->put("script_label", event["script"].toString());
|
||||
coord->put("event_group_type", "coord_event_group");
|
||||
map->events["coord_event_group"].append(coord);
|
||||
coord->put("event_group_type", EventGroup::Coord);
|
||||
map->events[EventGroup::Coord].append(coord);
|
||||
} else if (type == "weather") {
|
||||
Event *coord = new Event(event, EventType::WeatherTrigger);
|
||||
coord->put("map_name", map->name);
|
||||
|
@ -311,15 +336,15 @@ bool Project::loadMapData(Map* map) {
|
|||
coord->put("y", QString::number(event["y"].toInt()));
|
||||
coord->put("elevation", QString::number(event["elevation"].toInt()));
|
||||
coord->put("weather", event["weather"].toString());
|
||||
coord->put("event_group_type", "coord_event_group");
|
||||
coord->put("event_group_type", EventGroup::Coord);
|
||||
coord->put("event_type", EventType::WeatherTrigger);
|
||||
map->events["coord_event_group"].append(coord);
|
||||
map->events[EventGroup::Coord].append(coord);
|
||||
} else {
|
||||
logError(QString("Map %1 coord_event %2 has invalid type '%3'. Must be 'trigger' or 'weather'.").arg(map->name).arg(i).arg(type));
|
||||
}
|
||||
}
|
||||
|
||||
map->events["bg_event_group"].clear();
|
||||
map->events[EventGroup::Bg].clear();
|
||||
QJsonArray bgEventsArr = mapObj["bg_events"].toArray();
|
||||
for (int i = 0; i < bgEventsArr.size(); i++) {
|
||||
QJsonObject event = bgEventsArr[i].toObject();
|
||||
|
@ -332,8 +357,8 @@ bool Project::loadMapData(Map* map) {
|
|||
bg->put("elevation", QString::number(event["elevation"].toInt()));
|
||||
bg->put("player_facing_direction", event["player_facing_dir"].toString());
|
||||
bg->put("script_label", event["script"].toString());
|
||||
bg->put("event_group_type", "bg_event_group");
|
||||
map->events["bg_event_group"].append(bg);
|
||||
bg->put("event_group_type", EventGroup::Bg);
|
||||
map->events[EventGroup::Bg].append(bg);
|
||||
} else if (type == "hidden_item") {
|
||||
Event *bg = new Event(event, EventType::HiddenItem);
|
||||
bg->put("map_name", map->name);
|
||||
|
@ -348,8 +373,8 @@ bool Project::loadMapData(Map* map) {
|
|||
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
|
||||
bg->put("underfoot", event["underfoot"].toBool());
|
||||
}
|
||||
bg->put("event_group_type", "bg_event_group");
|
||||
map->events["bg_event_group"].append(bg);
|
||||
bg->put("event_group_type", EventGroup::Bg);
|
||||
map->events[EventGroup::Bg].append(bg);
|
||||
} else if (type == "secret_base") {
|
||||
Event *bg = new Event(event, EventType::SecretBase);
|
||||
bg->put("map_name", map->name);
|
||||
|
@ -357,8 +382,8 @@ bool Project::loadMapData(Map* map) {
|
|||
bg->put("y", QString::number(event["y"].toInt()));
|
||||
bg->put("elevation", QString::number(event["elevation"].toInt()));
|
||||
bg->put("secret_base_id", event["secret_base_id"].toString());
|
||||
bg->put("event_group_type", "bg_event_group");
|
||||
map->events["bg_event_group"].append(bg);
|
||||
bg->put("event_group_type", EventGroup::Bg);
|
||||
map->events[EventGroup::Bg].append(bg);
|
||||
} else {
|
||||
logError(QString("Map %1 bg_event %2 has invalid type '%3'. Must be 'sign', 'hidden_item', or 'secret_base'.").arg(map->name).arg(i).arg(type));
|
||||
}
|
||||
|
@ -861,8 +886,8 @@ void Project::saveHealLocationStruct(Map *map) {
|
|||
}
|
||||
|
||||
// set new location in healLocations list
|
||||
if (map->events["heal_event_group"].length() > 0) {
|
||||
for (Event *healEvent : map->events["heal_event_group"]) {
|
||||
if (map->events[EventGroup::Heal].length() > 0) {
|
||||
for (Event *healEvent : map->events[EventGroup::Heal]) {
|
||||
HealLocation hl = HealLocation::fromEvent(healEvent);
|
||||
healLocations[hl.index - 1] = hl;
|
||||
}
|
||||
|
@ -1333,17 +1358,23 @@ void Project::saveMap(Map *map) {
|
|||
if (map->sharedEventsMap.isEmpty()) {
|
||||
// Object events
|
||||
OrderedJson::array objectEventsArr;
|
||||
for (int i = 0; i < map->events["object_event_group"].length(); i++) {
|
||||
Event *object_event = map->events["object_event_group"].value(i);
|
||||
OrderedJson::object eventObj = object_event->buildObjectEventJSON();
|
||||
objectEventsArr.push_back(eventObj);
|
||||
for (int i = 0; i < map->events[EventGroup::Object].length(); i++) {
|
||||
Event *event = map->events[EventGroup::Object].value(i);
|
||||
QString event_type = event->get("event_type");
|
||||
OrderedJson::object jsonObj;
|
||||
if (event_type == EventType::Object) {
|
||||
jsonObj = event->buildObjectEventJSON();
|
||||
} else if (event_type == EventType::CloneObject) {
|
||||
jsonObj = event->buildCloneObjectEventJSON(mapNamesToMapConstants);
|
||||
}
|
||||
objectEventsArr.push_back(jsonObj);
|
||||
}
|
||||
mapObj["object_events"] = objectEventsArr;
|
||||
|
||||
// Warp events
|
||||
OrderedJson::array warpEventsArr;
|
||||
for (int i = 0; i < map->events["warp_event_group"].length(); i++) {
|
||||
Event *warp_event = map->events["warp_event_group"].value(i);
|
||||
for (int i = 0; i < map->events[EventGroup::Warp].length(); i++) {
|
||||
Event *warp_event = map->events[EventGroup::Warp].value(i);
|
||||
OrderedJson::object warpObj = warp_event->buildWarpEventJSON(mapNamesToMapConstants);
|
||||
warpEventsArr.append(warpObj);
|
||||
}
|
||||
|
@ -1351,8 +1382,8 @@ void Project::saveMap(Map *map) {
|
|||
|
||||
// Coord events
|
||||
OrderedJson::array coordEventsArr;
|
||||
for (int i = 0; i < map->events["coord_event_group"].length(); i++) {
|
||||
Event *event = map->events["coord_event_group"].value(i);
|
||||
for (int i = 0; i < map->events[EventGroup::Coord].length(); i++) {
|
||||
Event *event = map->events[EventGroup::Coord].value(i);
|
||||
QString event_type = event->get("event_type");
|
||||
if (event_type == EventType::Trigger) {
|
||||
OrderedJson::object triggerObj = event->buildTriggerEventJSON();
|
||||
|
@ -1366,8 +1397,8 @@ void Project::saveMap(Map *map) {
|
|||
|
||||
// Bg Events
|
||||
OrderedJson::array bgEventsArr;
|
||||
for (int i = 0; i < map->events["bg_event_group"].length(); i++) {
|
||||
Event *event = map->events["bg_event_group"].value(i);
|
||||
for (int i = 0; i < map->events[EventGroup::Bg].length(); i++) {
|
||||
Event *event = map->events[EventGroup::Bg].value(i);
|
||||
QString event_type = event->get("event_type");
|
||||
if (event_type == EventType::Sign) {
|
||||
OrderedJson::object signObj = event->buildSignEventJSON();
|
||||
|
@ -1692,8 +1723,12 @@ bool Project::readWildMonData() {
|
|||
|
||||
OrderedJson::object wildMonObj;
|
||||
if (!parser.tryParseOrderedJsonFile(&wildMonObj, wildMonJsonFilepath)) {
|
||||
logError(QString("Failed to read wild encounters from %1").arg(wildMonJsonFilepath));
|
||||
return false;
|
||||
// Failing to read wild encounters data is not a critical error, just disable the
|
||||
// encounter editor and log a warning in case the user intended to have this data.
|
||||
projectConfig.setEncounterJsonActive(false);
|
||||
emit disableWildEncountersUI();
|
||||
logWarn(QString("Failed to read wild encounters from %1").arg(wildMonJsonFilepath));
|
||||
return true;
|
||||
}
|
||||
|
||||
for (OrderedJson subObjectRef : wildMonObj["wild_encounter_groups"].array_items()) {
|
||||
|
@ -2248,9 +2283,8 @@ bool Project::readObjEventGfxConstants() {
|
|||
QStringList objEventGfxPrefixes("\\bOBJ_EVENT_GFX_");
|
||||
QString filename = "include/constants/event_objects.h";
|
||||
fileWatcher.addPath(root + "/" + filename);
|
||||
QMap<QString, int> gfxDefines = parser.readCDefines(filename, objEventGfxPrefixes);
|
||||
this->gfxNames = gfxDefines.keys();
|
||||
if (this->gfxNames.isEmpty()) {
|
||||
this->gfxDefines = parser.readCDefines(filename, objEventGfxPrefixes);
|
||||
if (this->gfxDefines.isEmpty()) {
|
||||
logError(QString("Failed to read object event graphics constants from %1.").arg(filename));
|
||||
return false;
|
||||
}
|
||||
|
@ -2380,25 +2414,48 @@ void Project::setEventPixmap(Event * event, bool forceLoad) {
|
|||
event->spriteHeight = 16;
|
||||
event->usingSprite = false;
|
||||
|
||||
QString group_type = event->get("event_group_type");
|
||||
if (group_type == EventGroup::Object) {
|
||||
QString gfxName;
|
||||
QString movement;
|
||||
QString event_type = event->get("event_type");
|
||||
if (event_type == EventType::Object) {
|
||||
QString gfxName = event->get("sprite");
|
||||
if (event_type == EventType::CloneObject) {
|
||||
// Try to get the targeted object to clone
|
||||
int eventIndex = event->getInt("target_local_id") - 1;
|
||||
Map * clonedMap = getMap(event->get("target_map"));
|
||||
Event * clonedEvent = clonedMap ? clonedMap->events[EventGroup::Object].value(eventIndex, nullptr) : nullptr;
|
||||
if (clonedEvent && clonedEvent->get("event_type") == EventType::Object) {
|
||||
// Get graphics data from cloned object
|
||||
gfxName = clonedEvent->get("sprite");
|
||||
movement = clonedEvent->get("movement_type");
|
||||
} else {
|
||||
// Invalid object specified, use default graphics data (as would be shown in-game)
|
||||
gfxName = gfxDefines.key(0);
|
||||
movement = movementTypes.first();
|
||||
}
|
||||
// Update clone object's sprite text to match target object
|
||||
event->put("sprite", gfxName);
|
||||
} else {
|
||||
// Get graphics data of regular object
|
||||
gfxName = event->get("sprite");
|
||||
movement = event->get("movement_type");
|
||||
}
|
||||
EventGraphics * eventGfx = eventGraphicsMap.value(gfxName, nullptr);
|
||||
if (!eventGfx || eventGfx->spritesheet.isNull()) {
|
||||
// No sprite associated with this gfx constant.
|
||||
// Use default sprite instead.
|
||||
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(0, 0, 16, 16);
|
||||
} else {
|
||||
event->setFrameFromMovement(facingDirections.value(event->get("movement_type")));
|
||||
event->setFrameFromMovement(facingDirections.value(movement));
|
||||
event->setPixmapFromSpritesheet(eventGfx->spritesheet, eventGfx->spriteWidth, eventGfx->spriteHeight, eventGfx->inanimate);
|
||||
}
|
||||
} else if (event_type == EventType::Warp) {
|
||||
} else if (group_type == EventGroup::Warp) {
|
||||
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(16, 0, 16, 16);
|
||||
} else if (event_type == EventType::Trigger || event_type == EventType::WeatherTrigger) {
|
||||
} else if (group_type == EventGroup::Coord) {
|
||||
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(32, 0, 16, 16);
|
||||
} else if (event_type == EventType::Sign || event_type == EventType::HiddenItem || event_type == EventType::SecretBase) {
|
||||
} else if (group_type == EventGroup::Bg) {
|
||||
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(48, 0, 16, 16);
|
||||
} else if (event_type == EventType::HealLocation) {
|
||||
} else if (group_type == EventGroup::Heal) {
|
||||
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(64, 0, 16, 16);
|
||||
}
|
||||
}
|
||||
|
@ -2413,7 +2470,8 @@ bool Project::readEventGraphics() {
|
|||
|
||||
qDeleteAll(eventGraphicsMap);
|
||||
eventGraphicsMap.clear();
|
||||
for (QString gfxName : this->gfxNames) {
|
||||
QStringList gfxNames = gfxDefines.keys();
|
||||
for (QString gfxName : gfxNames) {
|
||||
EventGraphics * eventGraphics = new EventGraphics;
|
||||
|
||||
QString info_label = pointerHash[gfxName].replace("&", "");
|
||||
|
@ -2473,8 +2531,8 @@ bool Project::readSpeciesIconPaths() {
|
|||
|
||||
void Project::saveMapHealEvents(Map *map) {
|
||||
// save heal event changes
|
||||
if (map->events["heal_event_group"].length() > 0) {
|
||||
for (Event *healEvent : map->events["heal_event_group"]) {
|
||||
if (map->events[EventGroup::Heal].length() > 0) {
|
||||
for (Event *healEvent : map->events[EventGroup::Heal]) {
|
||||
HealLocation hl = HealLocation::fromEvent(healEvent);
|
||||
healLocations[hl.index - 1] = hl;
|
||||
}
|
||||
|
@ -2483,11 +2541,11 @@ void Project::saveMapHealEvents(Map *map) {
|
|||
}
|
||||
|
||||
void Project::setNewMapEvents(Map *map) {
|
||||
map->events["object_event_group"].clear();
|
||||
map->events["warp_event_group"].clear();
|
||||
map->events["heal_event_group"].clear();
|
||||
map->events["coord_event_group"].clear();
|
||||
map->events["bg_event_group"].clear();
|
||||
map->events[EventGroup::Object].clear();
|
||||
map->events[EventGroup::Warp].clear();
|
||||
map->events[EventGroup::Heal].clear();
|
||||
map->events[EventGroup::Coord].clear();
|
||||
map->events[EventGroup::Bg].clear();
|
||||
}
|
||||
|
||||
int Project::getNumTilesPrimary()
|
||||
|
|
|
@ -26,15 +26,16 @@ void CityMapPixmapItem::init() {
|
|||
void CityMapPixmapItem::draw() {
|
||||
QImage image(width_ * 8, height_ * 8, QImage::Format_RGBA8888);
|
||||
|
||||
QPainter painter(&image);
|
||||
for (int i = 0; i < data.size() / 2; i++) {
|
||||
QImage img = this->tile_selector->tileImg(data[i * 2]);// need to skip every other tile
|
||||
int x = i % width_;
|
||||
int y = i / width_;
|
||||
QPoint pos = QPoint(x * 8, y * 8);
|
||||
painter.drawImage(pos, img);
|
||||
}
|
||||
painter.end();
|
||||
// TODO: construct temporary tile from this based on the id?
|
||||
// QPainter painter(&image);
|
||||
// for (int i = 0; i < data.size() / 2; i++) {
|
||||
// QImage img = this->tile_selector->tileImg(data[i * 2]);// need to skip every other tile
|
||||
// int x = i % width_;
|
||||
// int y = i / width_;
|
||||
// QPoint pos = QPoint(x * 8, y * 8);
|
||||
// painter.drawImage(pos, img);
|
||||
// }
|
||||
// painter.end();
|
||||
|
||||
this->setPixmap(QPixmap::fromImage(image));
|
||||
}
|
||||
|
|
|
@ -102,17 +102,24 @@ void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) {
|
|||
}
|
||||
|
||||
void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
|
||||
if (this->event->get("event_type") == EventType::Warp) {
|
||||
QString eventType = this->event->get("event_type");
|
||||
if (eventType == EventType::Warp) {
|
||||
QString destMap = this->event->get("destination_map_name");
|
||||
if (destMap != NONE_MAP_NAME) {
|
||||
emit editor->warpEventDoubleClicked(this->event->get("destination_map_name"), this->event->get("destination_warp"));
|
||||
emit editor->warpEventDoubleClicked(destMap, this->event->get("destination_warp"), EventGroup::Warp);
|
||||
}
|
||||
}
|
||||
else if (this->event->get("event_type") == EventType::SecretBase) {
|
||||
else if (eventType == EventType::CloneObject) {
|
||||
QString destMap = this->event->get("target_map");
|
||||
if (destMap != NONE_MAP_NAME) {
|
||||
emit editor->warpEventDoubleClicked(destMap, this->event->get("target_local_id"), EventGroup::Object);
|
||||
}
|
||||
}
|
||||
else if (eventType == EventType::SecretBase) {
|
||||
QString baseId = this->event->get("secret_base_id");
|
||||
QString destMap = editor->project->mapConstantsToMapNames.value("MAP_" + baseId.left(baseId.lastIndexOf("_")));
|
||||
if (destMap != NONE_MAP_NAME) {
|
||||
emit editor->warpEventDoubleClicked(destMap, "0");
|
||||
emit editor->warpEventDoubleClicked(destMap, "0", EventGroup::Warp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -371,11 +371,11 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
|
|||
for (Event *event : events) {
|
||||
editor->project->setEventPixmap(event);
|
||||
QString group = event->get("event_group_type");
|
||||
if ((showObjects && group == "object_event_group")
|
||||
|| (showWarps && group == "warp_event_group")
|
||||
|| (showBGs && group == "bg_event_group")
|
||||
|| (showTriggers && group == "coord_event_group")
|
||||
|| (showHealSpots && group == "heal_event_group"))
|
||||
if ((showObjects && group == EventGroup::Object)
|
||||
|| (showWarps && group == EventGroup::Warp)
|
||||
|| (showBGs && group == EventGroup::Bg)
|
||||
|| (showTriggers && group == EventGroup::Coord)
|
||||
|| (showHealSpots && group == EventGroup::Heal))
|
||||
eventPainter.drawImage(QPoint(event->getPixelX(), event->getPixelY()), event->pixmap.toImage());
|
||||
}
|
||||
eventPainter.end();
|
||||
|
|
|
@ -18,6 +18,10 @@ void NewEventToolButton::init()
|
|||
this->newObjectAction->setIcon(QIcon(":/icons/add.ico"));
|
||||
connect(this->newObjectAction, &QAction::triggered, this, &NewEventToolButton::newObject);
|
||||
|
||||
this->newCloneObjectAction = new QAction("New Clone Object", this);
|
||||
this->newCloneObjectAction->setIcon(QIcon(":/icons/add.ico"));
|
||||
connect(this->newCloneObjectAction, &QAction::triggered, this, &NewEventToolButton::newCloneObject);
|
||||
|
||||
this->newWarpAction = new QAction("New Warp", this);
|
||||
this->newWarpAction->setIcon(QIcon(":/icons/add.ico"));
|
||||
connect(this->newWarpAction, &QAction::triggered, this, &NewEventToolButton::newWarp);
|
||||
|
@ -50,6 +54,7 @@ void NewEventToolButton::init()
|
|||
|
||||
QMenu *alignMenu = new QMenu();
|
||||
alignMenu->addAction(this->newObjectAction);
|
||||
alignMenu->addAction(this->newCloneObjectAction);
|
||||
alignMenu->addAction(this->newWarpAction);
|
||||
//alignMenu->addAction(this->newHealLocationAction);
|
||||
alignMenu->addAction(this->newTriggerAction);
|
||||
|
@ -72,6 +77,12 @@ void NewEventToolButton::newObject()
|
|||
emit newEventAdded(this->selectedEventType);
|
||||
}
|
||||
|
||||
void NewEventToolButton::newCloneObject()
|
||||
{
|
||||
this->selectedEventType = EventType::CloneObject;
|
||||
emit newEventAdded(this->selectedEventType);
|
||||
}
|
||||
|
||||
void NewEventToolButton::newWarp()
|
||||
{
|
||||
this->selectedEventType = EventType::Warp;
|
||||
|
|
|
@ -156,6 +156,8 @@ void NewMapPopup::setDefaultValuesImportMap(MapLayout *mapLayout) {
|
|||
ui->comboBox_NewMap_Group->addItems(project->groupNames);
|
||||
ui->comboBox_NewMap_Group->setCurrentText(project->groupNames.at(0));
|
||||
|
||||
ui->comboBox_Song->addItems(project->songNames);
|
||||
|
||||
ui->spinBox_NewMap_Width->setValue(mapLayout->width.toInt(nullptr, 0));
|
||||
ui->spinBox_NewMap_Height->setValue(mapLayout->height.toInt(nullptr, 0));
|
||||
ui->comboBox_NewMap_Primary_Tileset->setCurrentText(mapLayout->tileset_primary_label);
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
void RegionMapEntriesPixmapItem::draw() {
|
||||
if (!region_map) return;
|
||||
|
||||
RegionMapEntry entry = region_map->mapSecToMapEntry.value(currentSection);
|
||||
MapSectionEntry entry = this->region_map->getEntry(currentSection);
|
||||
bool selectingEntry = false;
|
||||
|
||||
int entry_x, entry_y, entry_w, entry_h;
|
||||
|
||||
if (entry.name.isEmpty() || entry.name == "MAPSEC_NONE") {
|
||||
if (!entry.valid || entry.name == "MAPSEC_NONE") {
|
||||
entry_x = entry_y = 0;
|
||||
entry_w = entry_h = 1;
|
||||
} else {
|
||||
|
@ -17,25 +17,25 @@ void RegionMapEntriesPixmapItem::draw() {
|
|||
entry_w = entry.width, entry_h = entry.height;
|
||||
}
|
||||
|
||||
QImage image(region_map->width() * 8, region_map->height() * 8, QImage::Format_RGBA8888);
|
||||
QImage image(region_map->tilemapWidth() * 8, region_map->tilemapHeight() * 8, QImage::Format_RGBA8888);
|
||||
|
||||
QPainter painter(&image);
|
||||
for (int i = 0; i < region_map->map_squares.size(); i++) {
|
||||
QImage bottom_img = this->tile_selector->tileImg(region_map->map_squares[i].tile_img_id);
|
||||
for (int i = 0; i < region_map->tilemapSize(); i++) {
|
||||
QImage bottom_img = this->tile_selector->tileImg(region_map->getTile(i));
|
||||
QImage top_img(8, 8, QImage::Format_RGBA8888);
|
||||
int x = i % region_map->width();
|
||||
int y = i / region_map->width();
|
||||
int x = i % region_map->tilemapWidth();
|
||||
int y = i / region_map->tilemapWidth();
|
||||
bool insideEntry = false;
|
||||
if (selectingEntry) {
|
||||
if (x == entry_x + this->region_map->padLeft && y == entry_y + this->region_map->padTop)
|
||||
if (x == entry_x + this->region_map->padLeft() && y == entry_y + this->region_map->padTop())
|
||||
insideEntry = true;
|
||||
else if (x - this->region_map->padLeft - entry_x < entry_w && x >= entry_x + this->region_map->padLeft
|
||||
&& y - this->region_map->padTop - entry_y < entry_h && y >= entry_y + this->region_map->padTop)
|
||||
else if (x - this->region_map->padLeft() - entry_x < entry_w && x >= entry_x + this->region_map->padLeft()
|
||||
&& y - this->region_map->padTop() - entry_y < entry_h && y >= entry_y + this->region_map->padTop())
|
||||
insideEntry = true;
|
||||
}
|
||||
if (insideEntry) {
|
||||
top_img.fill(QColor(255, 68, 68));
|
||||
} else if (region_map->map_squares[i].has_map) {
|
||||
} else if (region_map->squareHasMap(i)) {
|
||||
top_img.fill(Qt::gray);
|
||||
} else {
|
||||
top_img.fill(Qt::black);
|
||||
|
@ -44,7 +44,7 @@ void RegionMapEntriesPixmapItem::draw() {
|
|||
painter.setOpacity(1);
|
||||
painter.drawImage(pos, bottom_img);
|
||||
painter.save();
|
||||
painter.setOpacity(0.55);
|
||||
painter.setOpacity(0.65);
|
||||
painter.drawImage(pos, top_img);
|
||||
painter.restore();
|
||||
}
|
||||
|
@ -54,7 +54,8 @@ void RegionMapEntriesPixmapItem::draw() {
|
|||
this->selectionOffsetY = entry_h - 1;
|
||||
|
||||
this->setPixmap(QPixmap::fromImage(image));
|
||||
this->drawSelection();
|
||||
|
||||
if (selectingEntry) this->drawSelection();
|
||||
}
|
||||
|
||||
void RegionMapEntriesPixmapItem::select(int x, int y) {
|
||||
|
@ -63,25 +64,25 @@ void RegionMapEntriesPixmapItem::select(int x, int y) {
|
|||
this->selectedTile = index;
|
||||
this->updateSelectedTile();
|
||||
|
||||
emit selectedTileChanged(this->region_map->map_squares[index].mapsec);
|
||||
emit selectedTileChanged(this->region_map->squareMapSection(index));
|
||||
}
|
||||
|
||||
void RegionMapEntriesPixmapItem::select(int index) {
|
||||
int x = index % this->region_map->width();
|
||||
int y = index / this->region_map->width();
|
||||
int x = index % this->region_map->tilemapWidth();
|
||||
int y = index / this->region_map->tilemapWidth();
|
||||
SelectablePixmapItem::select(x, y, 0, 0);
|
||||
this->selectedTile = index;
|
||||
this->updateSelectedTile();
|
||||
|
||||
emit selectedTileChanged(this->region_map->map_squares[index].mapsec);
|
||||
emit selectedTileChanged(this->region_map->squareMapSection(index));
|
||||
}
|
||||
|
||||
void RegionMapEntriesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
QPoint pos = this->getCellPos(event->pos());
|
||||
int x = pos.x() - this->region_map->padLeft;
|
||||
int y = pos.y() - this->region_map->padTop;
|
||||
int x = pos.x() - this->region_map->padLeft();
|
||||
int y = pos.y() - this->region_map->padTop();
|
||||
|
||||
RegionMapEntry entry = this->region_map->mapSecToMapEntry.value(currentSection);
|
||||
MapSectionEntry entry = this->region_map->getEntry(currentSection);
|
||||
pressedX = x - entry.x;
|
||||
pressedY = y - entry.y;
|
||||
if (entry.x == x && entry.y == y) {
|
||||
|
@ -92,6 +93,7 @@ void RegionMapEntriesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: update this function, especially bounds check
|
||||
void RegionMapEntriesPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
||||
if (!draggingEntry) {
|
||||
event->ignore();
|
||||
|
@ -99,14 +101,14 @@ void RegionMapEntriesPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|||
}
|
||||
|
||||
QPoint pos = this->getCellPos(event->pos());
|
||||
int new_x = pos.x() - this->region_map->padLeft - pressedX;
|
||||
int new_y = pos.y() - this->region_map->padTop - pressedY;
|
||||
int new_x = pos.x() - this->region_map->padLeft() - pressedX;
|
||||
int new_y = pos.y() - this->region_map->padTop() - pressedY;
|
||||
|
||||
RegionMapEntry entry = this->region_map->mapSecToMapEntry.value(currentSection);
|
||||
MapSectionEntry entry = this->region_map->getEntry(currentSection);
|
||||
|
||||
// check to make sure not moving out of bounds
|
||||
if (new_x + entry.width > this->region_map->width() - this->region_map->padLeft - this->region_map->padRight
|
||||
|| new_y + entry.height > this->region_map->height() - this->region_map->padTop - this->region_map->padBottom
|
||||
if (new_x + entry.width > this->region_map->tilemapWidth() - this->region_map->padLeft() //- this->region_map->padRight
|
||||
|| new_y + entry.height > this->region_map->tilemapHeight() - this->region_map->padTop() //- this->region_map->padBottom
|
||||
|| new_x < 0 || new_y < 0)
|
||||
return;
|
||||
|
||||
|
|
|
@ -3,24 +3,29 @@
|
|||
void RegionMapLayoutPixmapItem::draw() {
|
||||
if (!region_map) return;
|
||||
|
||||
QImage image(region_map->width() * 8, region_map->height() * 8, QImage::Format_RGBA8888);
|
||||
QImage image(region_map->pixelWidth(), region_map->pixelHeight(), QImage::Format_RGBA8888);
|
||||
|
||||
QPainter painter(&image);
|
||||
for (int i = 0; i < region_map->map_squares.size(); i++) {
|
||||
QImage bottom_img = this->tile_selector->tileImg(region_map->map_squares[i].tile_img_id);
|
||||
for (int i = 0; i < region_map->tilemapSize(); i++) {
|
||||
QImage bottom_img = this->tile_selector->tileImg(region_map->getTile(i));
|
||||
QImage top_img(8, 8, QImage::Format_RGBA8888);
|
||||
if (region_map->map_squares[i].has_map) {
|
||||
if (region_map->squareHasMap(i)) {
|
||||
top_img.fill(Qt::gray);
|
||||
} else {
|
||||
top_img.fill(Qt::black);
|
||||
}
|
||||
int x = i % region_map->width();
|
||||
int y = i / region_map->width();
|
||||
int x = i % region_map->tilemapWidth();
|
||||
int y = i / region_map->tilemapWidth();
|
||||
QPoint pos = QPoint(x * 8, y * 8);
|
||||
painter.setOpacity(1);
|
||||
painter.drawImage(pos, bottom_img);
|
||||
painter.save();
|
||||
if (region_map->squareInLayout(x, y)) {
|
||||
painter.setOpacity(0.55);
|
||||
} else {
|
||||
painter.setOpacity(0.8);
|
||||
}
|
||||
|
||||
painter.drawImage(pos, top_img);
|
||||
painter.restore();
|
||||
}
|
||||
|
@ -40,8 +45,8 @@ void RegionMapLayoutPixmapItem::select(int x, int y) {
|
|||
}
|
||||
|
||||
void RegionMapLayoutPixmapItem::select(int index) {
|
||||
int x = index % this->region_map->width();
|
||||
int y = index / this->region_map->width();
|
||||
int x = index % this->region_map->tilemapWidth();
|
||||
int y = index / this->region_map->tilemapWidth();
|
||||
SelectablePixmapItem::select(x, y, 0, 0);
|
||||
this->selectedTile = index;
|
||||
this->updateSelectedTile();
|
||||
|
@ -51,15 +56,13 @@ void RegionMapLayoutPixmapItem::select(int index) {
|
|||
|
||||
void RegionMapLayoutPixmapItem::highlight(int x, int y, int red) {
|
||||
this->highlightedTile = red;
|
||||
SelectablePixmapItem::select(x + this->region_map->padLeft, y + this->region_map->padTop, 0, 0);
|
||||
SelectablePixmapItem::select(x + this->region_map->padLeft(), y + this->region_map->padTop(), 0, 0);
|
||||
draw();
|
||||
}
|
||||
|
||||
void RegionMapLayoutPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
QPoint pos = this->getCellPos(event->pos());
|
||||
int index = this->region_map->getMapSquareIndex(pos.x(), pos.y());
|
||||
if (this->region_map->map_squares[index].x >= 0
|
||||
&& this->region_map->map_squares[index].y >= 0) {
|
||||
if (this->region_map->squareInLayout(pos.x(), pos.y())) {
|
||||
SelectablePixmapItem::mousePressEvent(event);
|
||||
this->updateSelectedTile();
|
||||
emit selectedTileChanged(this->selectedTile);
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
#include "regionmappixmapitem.h"
|
||||
#include "regionmapeditcommands.h"
|
||||
|
||||
void RegionMapPixmapItem::draw() {
|
||||
if (!region_map) return;
|
||||
|
||||
QImage image(region_map->width() * 8, region_map->height() * 8, QImage::Format_RGBA8888);
|
||||
QImage image(region_map->pixelWidth(), region_map->pixelHeight(), QImage::Format_RGBA8888);
|
||||
|
||||
QPainter painter(&image);
|
||||
for (int i = 0; i < region_map->map_squares.size(); i++) {
|
||||
QImage img = this->tile_selector->tileImg(region_map->map_squares[i].tile_img_id);
|
||||
int x = i % region_map->width();
|
||||
int y = i / region_map->width();
|
||||
for (int i = 0; i < region_map->tilemapSize(); i++) {
|
||||
QImage img = this->tile_selector->tileImg(region_map->getTile(i));
|
||||
int x = i % region_map->tilemapWidth();
|
||||
int y = i / region_map->tilemapWidth();
|
||||
QPoint pos = QPoint(x * 8, y * 8);
|
||||
painter.drawImage(pos, img);
|
||||
}
|
||||
|
@ -23,8 +24,77 @@ void RegionMapPixmapItem::paint(QGraphicsSceneMouseEvent *event) {
|
|||
QPointF pos = event->pos();
|
||||
int x = static_cast<int>(pos.x()) / 8;
|
||||
int y = static_cast<int>(pos.y()) / 8;
|
||||
int index = x + y * region_map->width();
|
||||
this->region_map->map_squares[index].tile_img_id = this->tile_selector->selectedTile;
|
||||
int index = x + y * region_map->tilemapWidth();
|
||||
this->region_map->setTileData(index,
|
||||
this->tile_selector->selectedTile,
|
||||
this->tile_selector->tile_hFlip,
|
||||
this->tile_selector->tile_vFlip,
|
||||
this->tile_selector->tile_palette
|
||||
);
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
void RegionMapPixmapItem::floodFill(int x, int y, std::shared_ptr<TilemapTile> oldTile, std::shared_ptr<TilemapTile> newTile) {
|
||||
// out of bounds
|
||||
if (x < 0
|
||||
|| y < 0
|
||||
|| x >= this->region_map->tilemapWidth()
|
||||
|| y >= this->region_map->tilemapHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto tile = this->region_map->getTile(x, y);
|
||||
if (!tile->operator==(*oldTile) || tile->operator==(*newTile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int index = x + y * this->region_map->tilemapWidth();
|
||||
this->region_map->setTileData(index,
|
||||
newTile->id(),
|
||||
newTile->hFlip(),
|
||||
newTile->vFlip(),
|
||||
newTile->palette()
|
||||
);
|
||||
|
||||
floodFill(x + 1, y, oldTile, newTile);
|
||||
floodFill(x - 1, y, oldTile, newTile);
|
||||
floodFill(x, y + 1, oldTile, newTile);
|
||||
floodFill(x, y - 1, oldTile, newTile);
|
||||
}
|
||||
|
||||
void RegionMapPixmapItem::fill(QGraphicsSceneMouseEvent *event) {
|
||||
if (region_map) {
|
||||
QPointF pos = event->pos();
|
||||
int x = static_cast<int>(pos.x()) / 8;
|
||||
int y = static_cast<int>(pos.y()) / 8;
|
||||
int index = x + y * this->region_map->tilemapWidth();
|
||||
std::shared_ptr<TilemapTile> currentTile, newTile, oldTile;
|
||||
currentTile = this->region_map->getTile(index);
|
||||
switch(this->tile_selector->format) {
|
||||
case TilemapFormat::Plain:
|
||||
oldTile = std::make_shared<PlainTile>(currentTile->raw());
|
||||
newTile = std::make_shared<PlainTile>(currentTile->raw());
|
||||
newTile->setId(this->tile_selector->selectedTile);
|
||||
break;
|
||||
case TilemapFormat::BPP_4:
|
||||
oldTile = std::make_shared<BPP4Tile>(currentTile->raw());
|
||||
newTile = std::make_shared<BPP4Tile>(currentTile->raw());
|
||||
newTile->setId(this->tile_selector->selectedTile);
|
||||
newTile->setHFlip(this->tile_selector->tile_hFlip);
|
||||
newTile->setVFlip(this->tile_selector->tile_vFlip);
|
||||
newTile->setPalette(this->tile_selector->tile_palette);
|
||||
break;
|
||||
case TilemapFormat::BPP_8:
|
||||
oldTile = std::make_shared<BPP8Tile>(currentTile->raw());
|
||||
newTile = std::make_shared<BPP8Tile>(currentTile->raw());
|
||||
newTile->setId(this->tile_selector->selectedTile);
|
||||
newTile->setId(this->tile_selector->selectedTile);
|
||||
newTile->setHFlip(this->tile_selector->tile_hFlip);
|
||||
newTile->setVFlip(this->tile_selector->tile_vFlip);
|
||||
break;
|
||||
}
|
||||
floodFill(x, y, oldTile, newTile);
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
@ -54,8 +124,8 @@ void RegionMapPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
|||
QPointF pos = event->pos();
|
||||
int x = static_cast<int>(pos.x()) / 8;
|
||||
int y = static_cast<int>(pos.y()) / 8;
|
||||
if (x < this->region_map->width() && x >= 0
|
||||
&& y < this->region_map->height() && y >= 0) {
|
||||
if (x < this->region_map->tilemapWidth() && x >= 0
|
||||
&& y < this->region_map->tilemapHeight() && y >= 0) {
|
||||
emit this->hoveredRegionMapTileChanged(x, y);
|
||||
emit mouseEvent(event, this);
|
||||
}
|
||||
|
|
257
src/ui/regionmappropertiesdialog.cpp
Normal file
|
@ -0,0 +1,257 @@
|
|||
#include "project.h"
|
||||
#include "regionmappropertiesdialog.h"
|
||||
#include "ui_regionmappropertiesdialog.h"
|
||||
|
||||
RegionMapPropertiesDialog::RegionMapPropertiesDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::RegionMapPropertiesDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->hideMessages();
|
||||
}
|
||||
|
||||
RegionMapPropertiesDialog::~RegionMapPropertiesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void RegionMapPropertiesDialog::hideMessages() {
|
||||
ui->message_alias->setVisible(false);
|
||||
ui->message_tilemapFormat->setVisible(false);
|
||||
ui->message_tilemapWidth->setVisible(false);
|
||||
ui->message_tilemapHeight->setVisible(false);
|
||||
ui->message_tilemapImagePath->setVisible(false);
|
||||
ui->message_tilemapBinPath->setVisible(false);
|
||||
ui->message_layoutFormat->setVisible(false);
|
||||
ui->message_layoutPath->setVisible(false);
|
||||
ui->message_layoutWidth->setVisible(false);
|
||||
ui->message_layoutHeight->setVisible(false);
|
||||
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
QString RegionMapPropertiesDialog::browse(QString filter, QFileDialog::FileMode mode) {
|
||||
if (!this->project) return QString();
|
||||
QFileDialog browser;
|
||||
browser.setFileMode(mode);
|
||||
QString filepath = browser.getOpenFileName(this, "Select a File", this->project->root, filter);
|
||||
|
||||
// remove the project root from the filepath
|
||||
return filepath.replace(this->project->root + "/", "");
|
||||
}
|
||||
|
||||
// TODO: test for missing fields/invalid cases
|
||||
void RegionMapPropertiesDialog::setProperties(poryjson::Json json) {
|
||||
poryjson::Json::object object = json.object_items();
|
||||
|
||||
// Region Map Properties
|
||||
ui->config_alias->setText(object["alias"].string_value());
|
||||
|
||||
// Tilemap properties
|
||||
poryjson::Json::object tilemap = object["tilemap"].object_items();
|
||||
ui->config_tilemapFormat->setCurrentText(tilemap["format"].string_value());
|
||||
ui->config_tilemapWidth->setValue(tilemap["width"].int_value());
|
||||
ui->config_tilemapHeight->setValue(tilemap["height"].int_value());
|
||||
|
||||
ui->config_tilemapImagePath->setText(tilemap["tileset_path"].string_value());
|
||||
ui->config_tilemapBinPath->setText(tilemap["tilemap_path"].string_value());
|
||||
if (tilemap.contains("palette"))
|
||||
ui->config_tilemapPalettePath->setText(tilemap["palette"].string_value());
|
||||
|
||||
// Layout props
|
||||
if (object["layout"].is_null()) {
|
||||
ui->group_layout->setChecked(false);
|
||||
} else {
|
||||
poryjson::Json::object layout = object["layout"].object_items();
|
||||
ui->config_layoutFormat->setCurrentText(layout["format"].string_value());
|
||||
ui->config_layoutPath->setText(layout["path"].string_value());
|
||||
ui->config_layoutWidth->setValue(layout["width"].int_value());
|
||||
ui->config_layoutHeight->setValue(layout["height"].int_value());
|
||||
ui->config_leftOffs->setValue(layout["offset_left"].int_value());
|
||||
ui->config_topOffs->setValue(layout["offset_top"].int_value());
|
||||
}
|
||||
}
|
||||
|
||||
poryjson::Json RegionMapPropertiesDialog::saveToJson() {
|
||||
poryjson::Json::object config;
|
||||
|
||||
// TODO: make sure next comment is not a lie
|
||||
// data should already be verified and valid at this point
|
||||
config["alias"] = ui->config_alias->text();
|
||||
|
||||
poryjson::Json::object tilemapObject;
|
||||
tilemapObject["width"] = ui->config_tilemapWidth->value();
|
||||
tilemapObject["height"] = ui->config_tilemapHeight->value();
|
||||
tilemapObject["format"] = ui->config_tilemapFormat->currentText();
|
||||
tilemapObject["tileset_path"] = ui->config_tilemapImagePath->text();
|
||||
tilemapObject["tilemap_path"] = ui->config_tilemapBinPath->text();
|
||||
tilemapObject["palette"] = ui->config_tilemapPalettePath->text();
|
||||
config["tilemap"] = tilemapObject;
|
||||
|
||||
if (ui->group_layout->isChecked()) {
|
||||
poryjson::Json::object layoutObject;
|
||||
layoutObject["format"] = ui->config_layoutFormat->currentText();
|
||||
layoutObject["path"] = ui->config_layoutPath->text();
|
||||
layoutObject["width"] = ui->config_layoutWidth->value();
|
||||
layoutObject["height"] = ui->config_layoutHeight->value();
|
||||
layoutObject["offset_left"] = ui->config_leftOffs->value();
|
||||
layoutObject["offset_top"] = ui->config_topOffs->value();
|
||||
config["layout"] = layoutObject;
|
||||
} else {
|
||||
config["layout"] = nullptr;
|
||||
}
|
||||
|
||||
return poryjson::Json(config);
|
||||
}
|
||||
|
||||
void RegionMapPropertiesDialog::on_browse_tilesetImagePath_clicked() {
|
||||
QString path = browse("Images (*.png *.bmp)", QFileDialog::ExistingFile);
|
||||
if (!path.isEmpty()) {
|
||||
ui->config_tilemapImagePath->setText(path);
|
||||
}
|
||||
}
|
||||
|
||||
void RegionMapPropertiesDialog::on_browse_tilemapBinPath_clicked() {
|
||||
QString path = browse("Binary (*.bin *.tilemap *.4bpp *.8bpp)", QFileDialog::AnyFile);
|
||||
if (!path.isEmpty()) {
|
||||
ui->config_tilemapBinPath->setText(path);
|
||||
}
|
||||
}
|
||||
|
||||
void RegionMapPropertiesDialog::on_browse_tilemapPalettePath_clicked() {
|
||||
QString path = browse("Text (*.pal)", QFileDialog::AnyFile);
|
||||
if (!path.isEmpty()) {
|
||||
ui->config_tilemapPalettePath->setText(path);
|
||||
}
|
||||
}
|
||||
|
||||
void RegionMapPropertiesDialog::on_browse_layoutPath_clicked() {
|
||||
if (ui->config_layoutFormat->currentIndex() == 0) {
|
||||
QString path = browse("Text File (*.h *.c *.inc *.txt)", QFileDialog::AnyFile);
|
||||
if (!path.isEmpty()) {
|
||||
ui->config_layoutPath->setText(path);
|
||||
}
|
||||
} else {
|
||||
QString path = browse("Binary (*.bin)", QFileDialog::AnyFile);
|
||||
if (!path.isEmpty()) {
|
||||
ui->config_layoutPath->setText(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegionMapPropertiesDialog::accept() {
|
||||
bool valid = true;
|
||||
|
||||
// verify alias is okay
|
||||
QString alias = ui->config_alias->text();
|
||||
if (alias.isEmpty()) {
|
||||
valid = false;
|
||||
ui->message_alias->setText("alias cannot be empty");
|
||||
ui->message_alias->setVisible(true);
|
||||
} else {
|
||||
QRegularExpression re("[A-Za-z0-9_\\- ]+");
|
||||
int temp = 0;
|
||||
QRegularExpressionValidator v(re, 0);
|
||||
|
||||
if (v.validate(alias, temp) != QValidator::Acceptable) {
|
||||
ui->message_alias->setText("this alias is not an acceptable string");
|
||||
ui->message_alias->setVisible(true);
|
||||
valid = false;
|
||||
}
|
||||
else { // no issues detected
|
||||
ui->message_alias->setText("");
|
||||
ui->message_alias->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
// tilemap properties
|
||||
// tilemap dimensions are specific: 64x32, 32x64, 16x16, 32x32, 64x64, 128x128
|
||||
// TODO: why is 30x20 allowed in firered?
|
||||
int tilemapWidth = ui->config_tilemapWidth->value();
|
||||
int tilemapHeight = ui->config_tilemapHeight->value();
|
||||
QMap<int, QList<int>> acceptableDimensions = { {16, {16}}, {30, {20}}, {32, {32, 64}}, {64, {32, 64}}, {128, {128}} };
|
||||
if (!acceptableDimensions.contains(tilemapWidth)) {
|
||||
// width not valid
|
||||
valid = false;
|
||||
ui->message_tilemapWidth->setText("tilemap width not valid, must be one of [16, 32, 64, 128]");
|
||||
ui->message_tilemapWidth->setVisible(true);
|
||||
} else {
|
||||
ui->message_tilemapWidth->setText("");
|
||||
ui->message_tilemapWidth->setVisible(false);
|
||||
// check width, height combo
|
||||
if (!acceptableDimensions.value(tilemapWidth).contains(tilemapHeight)) {
|
||||
valid = false;
|
||||
QString options = "";
|
||||
for (int i : acceptableDimensions.value(tilemapWidth))
|
||||
options += QString::number(i) + ", ";
|
||||
options.chop(2);
|
||||
ui->message_tilemapHeight->setText("tilemap height not valid, must be one of [" + options + "]");
|
||||
ui->message_tilemapHeight->setVisible(true);
|
||||
}
|
||||
else { // no issues detected
|
||||
ui->message_tilemapHeight->setText("");
|
||||
ui->message_tilemapHeight->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
// layout dimensions
|
||||
// need to verify <= tilemap dimensions, only req here
|
||||
int width = ui->config_layoutWidth->value() + ui->config_leftOffs->value();
|
||||
int height = ui->config_layoutHeight->value() + ui->config_topOffs->value();
|
||||
if (width > tilemapWidth) {
|
||||
valid = false;
|
||||
ui->message_layoutWidth->setText("layout map width + left offset cannot be larger than tilemap width");
|
||||
ui->message_layoutWidth->setVisible(true);
|
||||
} else {
|
||||
ui->message_layoutWidth->setText("");
|
||||
ui->message_layoutWidth->setVisible(false);
|
||||
}
|
||||
if (height > tilemapHeight) {
|
||||
valid = false;
|
||||
ui->message_layoutHeight->setText("layout map height + top offset cannot be larger than tilemap height");
|
||||
ui->message_layoutHeight->setVisible(true);
|
||||
} else {
|
||||
ui->message_layoutHeight->setText("");
|
||||
ui->message_layoutHeight->setVisible(false);
|
||||
}
|
||||
|
||||
// make sure paths arent empty
|
||||
if (ui->config_tilemapImagePath->text().isEmpty()) {
|
||||
valid = false;
|
||||
ui->message_tilemapImagePath->setText("this path cannot be empty");
|
||||
ui->message_tilemapImagePath->setVisible(true);
|
||||
} else {
|
||||
ui->message_tilemapImagePath->setText("");
|
||||
ui->message_tilemapImagePath->setVisible(false);
|
||||
}
|
||||
|
||||
if (ui->config_tilemapBinPath->text().isEmpty()) {
|
||||
valid = false;
|
||||
ui->message_tilemapBinPath->setText("this path cannot be empty");
|
||||
ui->message_tilemapBinPath->setVisible(true);
|
||||
} else {
|
||||
ui->message_tilemapBinPath->setText("");
|
||||
ui->message_tilemapBinPath->setVisible(false);
|
||||
}
|
||||
|
||||
// layout path only needs to exist if layout is enabled (obviously)
|
||||
if (ui->group_layout->isChecked()) {
|
||||
if (ui->config_layoutPath->text().isEmpty()) {
|
||||
valid = false;
|
||||
ui->message_layoutPath->setText("this path cannot be empty");
|
||||
ui->message_layoutPath->setVisible(true);
|
||||
} else {
|
||||
ui->message_layoutPath->setText("");
|
||||
ui->message_layoutPath->setVisible(false);
|
||||
}
|
||||
} else {
|
||||
ui->message_layoutPath->setText("");
|
||||
ui->message_layoutPath->setVisible(false);
|
||||
}
|
||||
|
||||
// TODO: limitations for map width/height if implementing
|
||||
|
||||
if (valid) {
|
||||
QDialog::accept();
|
||||
}
|
||||
}
|
|
@ -3,16 +3,16 @@
|
|||
#include <QDebug>
|
||||
|
||||
void TilemapTileSelector::draw() {
|
||||
size_t width_ = this->tilemap.width();
|
||||
size_t width_ = this->tileset.width();
|
||||
this->pixelWidth = width_;
|
||||
size_t height_ = this->tilemap.height();
|
||||
size_t height_ = this->tileset.height();
|
||||
this->pixelHeight = height_;
|
||||
size_t ntiles_ = (width_/8) * (height_/8);
|
||||
|
||||
this->numTilesWide = width_ / 8;
|
||||
this->numTiles = ntiles_;
|
||||
|
||||
this->setPixmap(tilemap);
|
||||
this->setPixmap(QPixmap::fromImage(this->setPalette(this->tile_palette)));
|
||||
this->drawSelection();
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ void TilemapTileSelector::select(unsigned tileId) {
|
|||
QPoint coords = this->getTileIdCoords(tileId);
|
||||
SelectablePixmapItem::select(coords.x(), coords.y(), 0, 0);
|
||||
this->selectedTile = tileId;
|
||||
this->drawSelection();
|
||||
emit selectedTileChanged(tileId);
|
||||
}
|
||||
|
||||
|
@ -28,10 +29,6 @@ void TilemapTileSelector::updateSelectedTile() {
|
|||
this->selectedTile = this->getTileId(origin.x(), origin.y());
|
||||
}
|
||||
|
||||
unsigned TilemapTileSelector::getSelectedTile() {
|
||||
return this->selectedTile;
|
||||
}
|
||||
|
||||
unsigned TilemapTileSelector::getTileId(int x, int y) {
|
||||
unsigned index = y * this->numTilesWide + x;
|
||||
return index < this->numTiles ? index : this->numTiles % index;
|
||||
|
@ -42,9 +39,63 @@ QPoint TilemapTileSelector::getTileIdCoords(unsigned tileId) {
|
|||
return QPoint(index % this->numTilesWide, index / this->numTilesWide);
|
||||
}
|
||||
|
||||
QImage TilemapTileSelector::tileImg(unsigned tileId) {
|
||||
QImage TilemapTileSelector::setPalette(int paletteIndex) {
|
||||
QImage tilesetImage = this->tileset;
|
||||
tilesetImage.convertTo(QImage::Format::Format_Indexed8);
|
||||
|
||||
// TODO: bounds check on the palette copying
|
||||
switch(this->format) {
|
||||
case TilemapFormat::Plain:
|
||||
break;
|
||||
case TilemapFormat::BPP_4:
|
||||
{
|
||||
QVector<QRgb> newColorTable;
|
||||
int palMinLength = paletteIndex * 16 + 16;
|
||||
if ((this->palette.count() < palMinLength) || (tilesetImage.colorTable().count() != 16)) {
|
||||
// either a) the palette has less than 256 colors, or b) the image is improperly indexed
|
||||
for (QRgb color : tilesetImage.colorTable()) {
|
||||
int gray = qGray(color);
|
||||
newColorTable.append(qRgb(gray, gray, gray));
|
||||
}
|
||||
} else {
|
||||
// use actual pal
|
||||
// before Qt 6, the color table is a QVector which is deprecated now, and this method does not exits
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
newColorTable = this->palette.toVector().mid(paletteIndex * 16, 16);
|
||||
#else
|
||||
newColorTable = this->palette.mid(paletteIndex * 16, 16);
|
||||
#endif
|
||||
}
|
||||
tilesetImage.setColorTable(newColorTable);
|
||||
break;
|
||||
}
|
||||
case TilemapFormat::BPP_8:
|
||||
{
|
||||
if (tilesetImage.colorTable().count() == this->palette.count()) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
tilesetImage.setColorTable(this->palette.toVector());
|
||||
#else
|
||||
tilesetImage.setColorTable(this->palette);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
return tilesetImage;
|
||||
}
|
||||
|
||||
QImage TilemapTileSelector::tileImg(shared_ptr<TilemapTile> tile) {
|
||||
unsigned tileId = tile->id();
|
||||
QPoint pos = getTileIdCoords(tileId);
|
||||
return this->tilemap.copy(pos.x() * 8, pos.y() * 8, 8, 8).toImage();
|
||||
|
||||
QImage tilesetImage = setPalette(tile->palette());
|
||||
|
||||
// take a tile from the tileset
|
||||
QImage img = tilesetImage.copy(pos.x() * 8, pos.y() * 8, 8, 8);
|
||||
img = img.mirrored(tile->hFlip(), tile->vFlip());
|
||||
return img;
|
||||
}
|
||||
|
||||
void TilemapTileSelector::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
||||
|
|
|
@ -40,6 +40,7 @@ TilesetEditor::~TilesetEditor()
|
|||
delete selectedTilePixmapItem;
|
||||
delete selectedTileScene;
|
||||
delete metatileLayersScene;
|
||||
delete copiedMetatile;
|
||||
}
|
||||
|
||||
void TilesetEditor::update(Map *map, QString primaryTilesetLabel, QString secondaryTilesetLabel) {
|
||||
|
@ -76,8 +77,8 @@ bool TilesetEditor::selectMetatile(uint16_t metatileId) {
|
|||
return true;
|
||||
}
|
||||
|
||||
uint16_t TilesetEditor::getSelectedMetatile() {
|
||||
return this->metatileSelector->getSelectedMetatile();
|
||||
uint16_t TilesetEditor::getSelectedMetatileId() {
|
||||
return this->metatileSelector->getSelectedMetatileId();
|
||||
}
|
||||
|
||||
void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTilesetLabel) {
|
||||
|
@ -177,7 +178,7 @@ void TilesetEditor::initMetatileSelector()
|
|||
}
|
||||
|
||||
void TilesetEditor::initMetatileLayersItem() {
|
||||
Metatile *metatile = Tileset::getMetatile(this->getSelectedMetatile(), this->primaryTileset, this->secondaryTileset);
|
||||
Metatile *metatile = Tileset::getMetatile(this->getSelectedMetatileId(), this->primaryTileset, this->secondaryTileset);
|
||||
this->metatileLayersItem = new MetatileLayersItem(metatile, this->primaryTileset, this->secondaryTileset);
|
||||
connect(this->metatileLayersItem, &MetatileLayersItem::tileChanged,
|
||||
this, &TilesetEditor::onMetatileLayerTileChanged);
|
||||
|
@ -282,7 +283,7 @@ void TilesetEditor::refresh() {
|
|||
this->metatileLayersItem->setTilesets(this->primaryTileset, this->secondaryTileset);
|
||||
this->tileSelector->setTilesets(this->primaryTileset, this->secondaryTileset);
|
||||
this->metatileSelector->setTilesets(this->primaryTileset, this->secondaryTileset);
|
||||
this->metatileSelector->select(this->getSelectedMetatile());
|
||||
this->metatileSelector->select(this->getSelectedMetatileId());
|
||||
this->drawSelectedTiles();
|
||||
|
||||
if (metatileSelector) {
|
||||
|
@ -419,7 +420,7 @@ void TilesetEditor::onMetatileLayerTileChanged(int x, int y) {
|
|||
this->metatileLayersItem->draw();
|
||||
this->hasUnsavedChanges = true;
|
||||
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
}
|
||||
|
@ -486,7 +487,7 @@ void TilesetEditor::on_comboBox_metatileBehaviors_textActivated(const QString &m
|
|||
if (this->metatile) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->behavior = static_cast<uint16_t>(project->metatileBehaviorMap[metatileBehavior]);
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
this->hasUnsavedChanges = true;
|
||||
|
@ -510,7 +511,7 @@ void TilesetEditor::saveMetatileLabel()
|
|||
if (this->metatile && this->metatile->label != this->ui->lineEdit_metatileLabel->text()) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->label = this->ui->lineEdit_metatileLabel->text();
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
this->hasUnsavedChanges = true;
|
||||
|
@ -522,7 +523,7 @@ void TilesetEditor::on_comboBox_layerType_activated(int layerType)
|
|||
if (this->metatile) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->layerType = static_cast<uint8_t>(layerType);
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
this->hasUnsavedChanges = true;
|
||||
|
@ -534,7 +535,7 @@ void TilesetEditor::on_comboBox_encounterType_activated(int encounterType)
|
|||
if (this->metatile) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->encounterType = static_cast<uint8_t>(encounterType);
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
this->hasUnsavedChanges = true;
|
||||
|
@ -546,7 +547,7 @@ void TilesetEditor::on_comboBox_terrainType_activated(int terrainType)
|
|||
if (this->metatile) {
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
this->metatile->terrainType = static_cast<uint8_t>(terrainType);
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatile(),
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(this->getSelectedMetatileId(),
|
||||
prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
this->hasUnsavedChanges = true;
|
||||
|
@ -811,6 +812,21 @@ void TilesetEditor::onPaletteEditorChangedPalette(int paletteId) {
|
|||
this->on_spinBox_paletteSelector_valueChanged(paletteId);
|
||||
}
|
||||
|
||||
bool TilesetEditor::replaceMetatile(uint16_t metatileId, Metatile * src)
|
||||
{
|
||||
Metatile * dest = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
if (!dest || !src || *dest == *src)
|
||||
return false;
|
||||
|
||||
this->metatile = dest;
|
||||
*this->metatile = *src;
|
||||
this->metatileSelector->select(metatileId);
|
||||
this->metatileSelector->draw();
|
||||
this->metatileLayersItem->draw();
|
||||
this->metatileLayersItem->clearLastModifiedCoords();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionUndo_triggered()
|
||||
{
|
||||
MetatileHistoryItem *commit = this->metatileHistory.current();
|
||||
|
@ -818,34 +834,39 @@ void TilesetEditor::on_actionUndo_triggered()
|
|||
Metatile *prev = commit->prevMetatile;
|
||||
if (!prev) return;
|
||||
this->metatileHistory.back();
|
||||
|
||||
Metatile *temp = Tileset::getMetatile(commit->metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
if (temp) {
|
||||
this->metatile = temp;
|
||||
*this->metatile = *prev;
|
||||
this->metatileSelector->select(commit->metatileId);
|
||||
this->metatileSelector->draw();
|
||||
this->metatileLayersItem->draw();
|
||||
this->metatileLayersItem->clearLastModifiedCoords();
|
||||
}
|
||||
this->replaceMetatile(commit->metatileId, prev);
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionRedo_triggered()
|
||||
{
|
||||
MetatileHistoryItem *commit = this->metatileHistory.next();
|
||||
if (!commit) return;
|
||||
Metatile *next = commit->newMetatile;
|
||||
if (!next) return;
|
||||
|
||||
Metatile *temp = Tileset::getMetatile(commit->metatileId, this->primaryTileset, this->secondaryTileset);
|
||||
if (temp) {
|
||||
this->metatile = temp;
|
||||
*this->metatile = *next;
|
||||
this->metatileSelector->select(commit->metatileId);
|
||||
this->metatileSelector->draw();
|
||||
this->metatileLayersItem->draw();
|
||||
this->metatileLayersItem->clearLastModifiedCoords();
|
||||
this->replaceMetatile(commit->metatileId, commit->newMetatile);
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionCopy_triggered()
|
||||
{
|
||||
Metatile * toCopy = Tileset::getMetatile(this->getSelectedMetatileId(), this->primaryTileset, this->secondaryTileset);
|
||||
if (!toCopy) return;
|
||||
|
||||
if (!this->copiedMetatile)
|
||||
this->copiedMetatile = new Metatile(*toCopy);
|
||||
else
|
||||
*this->copiedMetatile = *toCopy;
|
||||
this->copiedMetatile->label = ""; // Don't copy the label, these should be unique to each metatile
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionPaste_triggered()
|
||||
{
|
||||
Metatile *prevMetatile = new Metatile(*this->metatile);
|
||||
uint16_t metatileId = this->getSelectedMetatileId();
|
||||
if (!this->replaceMetatile(metatileId, this->copiedMetatile)) {
|
||||
delete prevMetatile;
|
||||
return;
|
||||
}
|
||||
|
||||
MetatileHistoryItem *commit = new MetatileHistoryItem(metatileId, prevMetatile, new Metatile(*this->metatile));
|
||||
metatileHistory.push(commit);
|
||||
}
|
||||
|
||||
void TilesetEditor::on_actionExport_Primary_Tiles_Image_triggered()
|
||||
|
|
|
@ -78,7 +78,7 @@ void TilesetEditorMetatileSelector::updateSelectedMetatile() {
|
|||
emit selectedMetatileChanged(this->selectedMetatile);
|
||||
}
|
||||
|
||||
uint16_t TilesetEditorMetatileSelector::getSelectedMetatile() {
|
||||
uint16_t TilesetEditorMetatileSelector::getSelectedMetatileId() {
|
||||
return this->selectedMetatile;
|
||||
}
|
||||
|
||||
|
|