Merge branch 'master' of https://github.com/huderlem/porymap into fix-json

This commit is contained in:
GriffinR 2022-10-17 22:20:06 -04:00
commit e2a31336c5
42 changed files with 4260 additions and 1833 deletions

View file

@ -11,22 +11,22 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
- Proper support for pokefirered's clone objects was added, which requires the changes made in [pokefirered/#484](https://github.com/pret/pokefirered/pull/484).
- Many API functions which were previously accessible via the `map` object are now accessible via one of the new objects `overlay`, `utility`, or `constants`. Some functions were renamed accordingly. See [porymap/#460](https://github.com/huderlem/porymap/pull/460) for a full list of API function name changes.
- Arguments for the API function `createImage` have changed: `xflip` and `yflip` have been replaced with `hScale` and `vScale`, and `offset` has been replaced with `xOffset` and `yOffset`.
- The API function `addFilledRect` has been removed; it's been replaced by new arguments in `addRect`: `color` has been replaced with `borderColor` and `fillColor`, and a new `rounding` argument allows ellipses to be drawn.
### Added
- Add prefab support
- Add Cut/Copy/Paste for metatiles in the Tileset Editor.
- Add new features to the scripting API, including the ability to display message boxes and user input windows, set overlay opacity, get/set map header properties, read/write the map border, read tile pixel data, and set blocks or metatile attributes using a raw value.
- Add button to copy the full metatile label to the clipboard in the Tileset Editor.
- Add ability to export an image of the primary or secondary tileset's metatiles.
- Add option to not open the most recent project on launch.
- Add options for customizing how new maps are filled
- Add color picker to palette editor for taking colors from the screen.
- Add new features to the scripting API, including the ability to display messages and user input windows, set the overlay's opacity, rotation, scale, and clipping, interact with map header properties and the map border, read tile pixel data, and more.
### Changed
- Overhauled the region map editor, adding support for tilemaps, and significant customization. Also now supports pokefirered.
- 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.
- Unused metatile attribute bits are preserved instead of being cleared.
- The wild encounter editor is automatically disabled if the encounter JSON data cannot be read
- Metatiles are always rendered accurately with 3 layers, and the unused layer is not assumed to be transparent.
- `object_event_graphics_info.h` can now be parsed correctly if it uses structs with attributes.
@ -34,6 +34,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
- The selection is no longer reset when pasting events. The newly pasted events are selected instead.
- Palette editor ui is updated a bit to allow hex and rgb value input.
- The metatile behavior is now displayed in the bottom bar mouseover text.
- Removed some unnecessary error logs from the scripting API and added new useful ones.
### Fixed
- Fix cursor tile outline not updating at the end of a dragged selection.
@ -43,8 +44,9 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
- Fix collision values of 2 or 3 not rendering properly.
- Fix the map music dropdown being empty when importing a map from Advance Map.
- Fix object events added by pasting ignoring the map event limit.
- Fixed a bug where saving the tileset editor would reselect the main editor's first selected metatile.
- Fix a bug where saving the tileset editor would reselect the main editor's first selected metatile.
- Fix crashes / unexpected behavior if certain scripting API functions are given invalid palette or tile numbers.
- Fix drawing large amounts of text with the scripting API causing a significant drop in performance.
- Silence unnecessary error logging when parsing C defines Porymap doesn't use.
- Fix some windows like the Tileset Editor not raising to the front when reactivated.

View file

@ -640,12 +640,13 @@ All tileset functions are callable via the global ``map`` object.
:param number paletteIndex: the palette index
:returns array: array of colors. Each color is a 3-element RGB array
.. js:function:: map.setPrimaryTilesetPalettePreview(paletteIndex, colors)
.. js:function:: map.setPrimaryTilesetPalettePreview(paletteIndex, colors, forceRedraw = true)
Sets a palette in the primary tileset of the currently-opened map. This will NOT affect the true underlying colors--it only displays these colors in the map-editing area of Porymap.
:param number paletteIndex: the palette index
:param array colors: array of colors. Each color is a 3-element RGB array
:param boolean forceRedraw: Redraw the elements with the updated palette. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
.. js:function:: map.getPrimaryTilesetPalettesPreview()
@ -653,11 +654,12 @@ All tileset functions are callable via the global ``map`` object.
:returns array: array of arrays of colors. Each color is a 3-element RGB array
.. js:function:: map.setPrimaryTilesetPalettesPreview(palettes)
.. js:function:: map.setPrimaryTilesetPalettesPreview(palettes, forceRedraw = true)
Sets all of the palettes in the primary tileset of the currently-opened map. This will NOT affect the true underlying colors--it only displays these colors in the map-editing area of Porymap.
:param array palettes: array of arrays of colors. Each color is a 3-element RGB array
:param boolean forceRedraw: Redraw the elements with the updated palettes. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
.. js:function:: map.getSecondaryTilesetPalettePreview(paletteIndex)
@ -666,12 +668,13 @@ All tileset functions are callable via the global ``map`` object.
:param number paletteIndex: the palette index
:returns array: array of colors. Each color is a 3-element RGB array
.. js:function:: map.setSecondaryTilesetPalettePreview(paletteIndex, colors)
.. js:function:: map.setSecondaryTilesetPalettePreview(paletteIndex, colors, forceRedraw = true)
Sets a palette in the secondary tileset of the currently-opened map. This will NOT affect the true underlying colors--it only displays these colors in the map-editing area of Porymap.
:param number paletteIndex: the palette index
:param array colors: array of colors. Each color is a 3-element RGB array
:param boolean forceRedraw: Redraw the elements with the updated palette. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
.. js:function:: map.getSecondaryTilesetPalettesPreview()
@ -679,11 +682,12 @@ All tileset functions are callable via the global ``map`` object.
:returns array: array of arrays of colors. Each color is a 3-element RGB array
.. js:function:: map.setSecondaryTilesetPalettesPreview(palettes)
.. js:function:: map.setSecondaryTilesetPalettesPreview(palettes, forceRedraw = true)
Sets all of the palettes in the secondary tileset of the currently-opened map. This will NOT affect the true underlying colors--it only displays these colors in the map-editing area of Porymap.
:param array palettes: array of arrays of colors. Each color is a 3-element RGB array
:param boolean forceRedraw: Redraw the elements with the updated palettes. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
.. js:function:: map.getPrimaryTilesetPalette(paletteIndex)
@ -692,12 +696,13 @@ All tileset functions are callable via the global ``map`` object.
:param number paletteIndex: the palette index
:returns array: array of colors. Each color is a 3-element RGB array
.. js:function:: map.setPrimaryTilesetPalette(paletteIndex, colors)
.. js:function:: map.setPrimaryTilesetPalette(paletteIndex, colors, forceRedraw = true)
Sets a palette in the primary tileset of the currently-opened map. This will permanently affect the palette and save the palette to disk.
:param number paletteIndex: the palette index
:param array colors: array of colors. Each color is a 3-element RGB array
:param boolean forceRedraw: Redraw the elements with the updated palette. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
.. js:function:: map.getPrimaryTilesetPalettes()
@ -705,11 +710,12 @@ All tileset functions are callable via the global ``map`` object.
:returns array: array of arrays of colors. Each color is a 3-element RGB array
.. js:function:: map.setPrimaryTilesetPalettes(palettes)
.. js:function:: map.setPrimaryTilesetPalettes(palettes, forceRedraw = true)
Sets all of the palettes in the primary tileset of the currently-opened map. This will permanently affect the palettes and save the palettes to disk.
:param array palettes: array of arrays of colors. Each color is a 3-element RGB array
:param boolean forceRedraw: Redraw the elements with the updated palettes. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
.. js:function:: map.getSecondaryTilesetPalette(paletteIndex)
@ -718,12 +724,13 @@ All tileset functions are callable via the global ``map`` object.
:param number paletteIndex: the palette index
:returns array: array of colors. Each color is a 3-element RGB array
.. js:function:: map.setSecondaryTilesetPalette(paletteIndex, colors)
.. js:function:: map.setSecondaryTilesetPalette(paletteIndex, colors, forceRedraw = true)
Sets a palette in the secondary tileset of the currently-opened map. This will permanently affect the palette and save the palette to disk.
:param number paletteIndex: the palette index
:param array colors: array of colors. Each color is a 3-element RGB array
:param boolean forceRedraw: Redraw the elements with the updated palette. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
.. js:function:: map.getSecondaryTilesetPalettes()
@ -731,11 +738,12 @@ All tileset functions are callable via the global ``map`` object.
:returns array: array of arrays of colors. Each color is a 3-element RGB array
.. js:function:: map.setSecondaryTilesetPalettes(palettes)
.. js:function:: map.setSecondaryTilesetPalettes(palettes, forceRedraw = true)
Sets all of the palettes in the secondary tileset of the currently-opened map. This will permanently affect the palettes and save the palettes to disk.
:param array palettes: array of arrays of colors. Each color is a 3-element RGB array
:param boolean forceRedraw: Redraw the elements with the updated palettes. Defaults to ``true``. Redrawing the elements that use palettes is expensive, so it can be useful to batch together many calls to palette functions and only set ``redraw`` to ``true`` on the final call.
.. js:function:: map.getMetatileLayerOrder()
@ -936,7 +944,7 @@ All tileset functions are callable via the global ``map`` object.
Overlay Functions
^^^^^^^^^^^^^^^^^
The following functions are related to an overlay that is drawn on top of the map area. Text, images, and shapes can be drawn using these functions. Items can be drawn and manipulated on separate layers by specifiying a layer id. Items on higher layer ids will be drawn above those on lower layers. The visibility, position, and opacity of each layer can be changed; by default all layers are visible, at position ``0,0``, and have an opacity of ``100``.
The following functions are related to an overlay that is drawn on top of the map area. Text, images, and shapes can be drawn using these functions. Items can be drawn and manipulated on separate layers by specifiying a layer id. Items on higher layer ids will be drawn above those on lower layers. The visibility, opacity, position, rotation, and scale of each layer can be changed; by default all layers are visible, have an opacity of ``100``, are at position ``0,0``, an angle of ``0``, and a horizontal and vertical scale of ``1.0``.
All overlay functions are callable via the global ``overlay`` object.
@ -1010,6 +1018,79 @@ All overlay functions are callable via the global ``overlay`` object.
:param number opacity: the opacity
.. js:function:: overlay.getHorizontalScale(layer = 0)
Gets the horizontal scale of the specified overlay layer. ``1.0`` is normal size.
:param number layer: the layer id. Defaults to ``0``
:returns number: the scale
.. js:function:: overlay.getVerticalScale(layer = 0)
Gets the vertical scale of the specified overlay layer. ``1.0`` is normal size.
:param number layer: the layer id. Defaults to ``0``
:returns number: the scale
.. js:function:: overlay.setHorizontalScale(scale, layer)
Sets the horizontal scale of the specified overlay layer. ``1.0`` is normal size.
:param number scale: the scale to set
:param number layer: the layer id
.. js:function:: overlay.setHorizontalScale(scale)
This is an overloaded function. Sets the horizontal scale of all active overlay layers. Layers that have not been used yet will not have their scale changed. ``1.0`` is normal size.
:param number scale: the scale to set
.. js:function:: overlay.setVerticalScale(scale, layer)
Sets the vertical scale of the specified overlay layer. ``1.0`` is normal size.
:param number scale: the scale to set
:param number layer: the layer id
.. js:function:: overlay.setVerticalScale(scale)
This is an overloaded function. Sets the vertical scale of all active overlay layers. Layers that have not been used yet will not have their scale changed. ``1.0`` is normal size.
:param number scale: the scale to set
.. js:function:: overlay.getRotation(layer = 0)
Gets the angle the specified overlay layer is rotated to.
:param number layer: the layer id. Defaults to ``0``
:returns number: the angle the layer is rotated to
.. js:function:: overlay.setRotation(angle, layer)
Sets the angle the specified overlay layer is rotated to.
:param number angle: the angle to set
:param number layer: the layer id
.. js:function:: overlay.setRotation(angle)
This is an overloaded function. Sets the angle that all active overlay layers are rotated to. Layers that have not been used yet will not have their angle changed.
:param number angle: the angle to set
.. js:function:: overlay.rotate(degrees, layer)
Rotates the specified overlay layer. A positive number of degrees is clockwise rotation, a negative number of degrees is counterclockwise rotation.
:param number degrees: the number of degrees to rotate
:param number layer: the layer id
.. js:function:: overlay.rotate(degrees)
This is an overloaded function. Rotates the all active overlay layers. Layers that have not been used yet will not be rotated. A positive number of degrees is clockwise rotation, a negative number of degrees is counterclockwise rotation.
:param number degrees: the number of degrees to rotate
.. js:function:: overlay.getX(layer = 0)
Gets the x position of the specified overlay layer.
@ -1123,11 +1204,11 @@ All overlay functions are callable via the global ``overlay`` object.
:param string text: the text to display
:param number x: the x pixel coordinate of the text (relative to the layer's position)
:param number y: the y pixel coordinate of the text (relative to the layer's position)
:param string color: the color of the text. Can be specified as "#RRGGBB" or "#AARRGGBB". Defaults to black.
:param string color: the color of the text. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to black.
:param number size: the font size of the text. Defaults to 12.
:param number layer: the layer id. Defaults to ``0``
.. js:function:: overlay.addRect(x, y, width, height, color = "#000000", layer = 0)
.. js:function:: overlay.addRect(x, y, width, height, borderColor = "#000000", fillColor = "", rounding = 0, layer = 0)
Adds a rectangle outline item to the specified overlay layer.
@ -1135,18 +1216,28 @@ All overlay functions are callable via the global ``overlay`` object.
:param number y: the y pixel coordinate of the rectangle's top-left corner (relative to the layer's position)
:param number width: the pixel width of the rectangle
:param number height: the pixel height of the rectangle
:param string color: the color of the rectangle. Can be specified as "#RRGGBB" or "#AARRGGBB". Defaults to black.
:param string borderColor: the color of the rectangle's border. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to black.
:param string fillColor: the color of the area enclosed by the rectangle. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to transparent.
:param number rounding: the percent degree the corners will be rounded. ``0`` is rectangular, ``100`` is elliptical. Defaults to ``0``
:param number layer: the layer id. Defaults to ``0``
.. js:function:: overlay.addFilledRect(x, y, width, height, color = "#000000", layer = 0)
.. js:function:: overlay.addPath(coords, borderColor = "#000000", fillColor = "", layer = 0)
Adds a filled rectangle item to the specified overlay layer.
Draws a straight path on the specified layer by connecting the coordinate pairs in ``coords``. The area enclosed by the path can be colored in, and will follow the `"odd-even" fill rule <https://doc.qt.io/qt-5/qt.html#FillRule-enum>`_.
:param number x: the x pixel coordinate of the rectangle's top-left corner (relative to the layer's position)
:param number y: the y pixel coordinate of the rectangle's top-left corner (relative to the layer's position)
:param number width: the pixel width of the rectangle
:param number height: the pixel height of the rectangle
:param string color: the color of the rectangle. Can be specified as "#RRGGBB" or "#AARRGGBB". Defaults to black.
:param array coords: array of pixel coordinates to connect to create the path. Each element of the array should be an array containing an x and y pixel coordinate
:param string borderColor: the color of the path. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to black.
:param string fillColor: the color of the area enclosed by the path. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to transparent.
:param number layer: the layer id. Defaults to ``0``
.. js:function:: overlay.addPath(xCoords, yCoords, borderColor = "#000000", fillColor = "", layer = 0)
This is an overloaded function. Draws a straight path on the specified layer by connecting the coordinates at (``xCoords``, ``yCoords``). The area enclosed by the path can be colored in, and will follow the `"odd-even" fill rule <https://doc.qt.io/qt-5/qt.html#FillRule-enum>`_.
:param array xCoords: array of x pixel coordinates to connect to create the path
:param array yCoords: array of y pixel coordinates to connect to create the path
:param string borderColor: the color of the path. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to black.
:param string fillColor: the color of the area enclosed by the path. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to transparent.
:param number layer: the layer id. Defaults to ``0``
.. js:function:: overlay.addImage(x, y, filepath, layer = 0, useCache = true)

View file

@ -813,8 +813,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>77</height>
<width>423</width>
<height>74</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_7">
@ -1001,10 +1001,10 @@
</property>
<property name="geometry">
<rect>
<x>0</x>
<x>8</x>
<y>0</y>
<width>411</width>
<height>449</height>
<height>413</height>
</rect>
</property>
<property name="sizePolicy">
@ -1155,7 +1155,7 @@
<x>0</x>
<y>0</y>
<width>428</width>
<height>704</height>
<height>696</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_7">
@ -1387,7 +1387,7 @@
</property>
<property name="minimumSize">
<size>
<width>330</width>
<width>0</width>
<height>0</height>
</size>
</property>
@ -1404,16 +1404,6 @@
<property name="bottomMargin">
<number>3</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_NoEvents">
<property name="text">
<string>There are no events on the current map.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QFrame" name="frame_4">
<property name="maximumSize">
@ -1423,11 +1413,14 @@
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
@ -1522,8 +1515,24 @@
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_NoEvents">
<property name="text">
<string>There are no events on the current map.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QTabWidget" name="tabWidget_EventType">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
</property>
@ -1544,8 +1553,57 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hbox_Objects">
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSpinBox" name="spinner_ObjectID">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_16_5">
<property name="text">
<string>object id</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QScrollArea" name="scrollArea_Objects">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -1557,8 +1615,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>98</width>
<height>28</height>
<width>434</width>
<height>581</height>
</rect>
</property>
<property name="sizePolicy">
@ -1589,8 +1647,57 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hbox_Warps">
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSpinBox" name="spinner_WarpID">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_16_1">
<property name="text">
<string>warp id</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QScrollArea" name="scrollArea_Warps">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -1602,8 +1709,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>98</width>
<height>28</height>
<width>434</width>
<height>581</height>
</rect>
</property>
<property name="sizePolicy">
@ -1634,8 +1741,57 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hbox_Triggers">
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSpinBox" name="spinner_TriggerID">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_16_2">
<property name="text">
<string>coord id</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QScrollArea" name="scrollArea_Triggers">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -1647,8 +1803,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>98</width>
<height>28</height>
<width>434</width>
<height>581</height>
</rect>
</property>
<property name="sizePolicy">
@ -1679,8 +1835,63 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hbox_BGs">
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSpinBox" name="spinner_BgID">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_16_3">
<property name="text">
<string>bg id</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QScrollArea" name="scrollArea_BGs">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -1692,8 +1903,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>98</width>
<height>28</height>
<width>434</width>
<height>581</height>
</rect>
</property>
<property name="sizePolicy">
@ -1724,8 +1935,57 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="hbox_Heals">
<property name="leftMargin">
<number>12</number>
</property>
<property name="topMargin">
<number>12</number>
</property>
<property name="rightMargin">
<number>12</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QSpinBox" name="spinner_HealID">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_16_4">
<property name="text">
<string>heal id</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QScrollArea" name="scrollArea_Healspots">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -1737,8 +1997,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>98</width>
<height>28</height>
<width>434</width>
<height>581</height>
</rect>
</property>
<property name="sizePolicy">
@ -1777,6 +2037,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -1788,8 +2051,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>98</width>
<height>28</height>
<width>434</width>
<height>625</height>
</rect>
</property>
<property name="sizePolicy">
@ -2684,7 +2947,7 @@
<x>0</x>
<y>0</y>
<width>1287</width>
<height>21</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">

View file

@ -1,123 +0,0 @@
#pragma once
#ifndef EVENT_H
#define EVENT_H
#include <QString>
#include <QPixmap>
#include <QMap>
#include "orderedjson.h"
using OrderedJson = poryjson::Json;
class EventType
{
public:
static QString Object;
static QString CloneObject;
static QString Warp;
static QString Trigger;
static QString WeatherTrigger;
static QString Sign;
static QString HiddenItem;
static QString SecretBase;
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
{
public:
Event();
Event(const Event&);
Event(QJsonObject, QString);
public:
int x() const {
return getInt("x");
}
int y() const {
return getInt("y");
}
int elevation() {
return getInt("elevation");
}
void setX(int x) {
put("x", x);
}
void setY(int y) {
put("y", y);
}
QString get(const QString &key) const {
return values.value(key);
}
int getInt(const QString &key) const {
return values.value(key).toInt(nullptr, 0);
}
uint16_t getU16(const QString &key) const {
return values.value(key).toUShort(nullptr, 0);
}
int16_t getS16(const QString &key) const {
return values.value(key).toShort(nullptr, 0);
}
void put(QString key, int value) {
put(key, QString("%1").arg(value));
}
void put(QString key, QString value) {
values.insert(key, value);
}
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*);
static Event* createNewWeatherTriggerEvent(Project*);
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();
OrderedJson::object buildSignEventJSON();
OrderedJson::object buildHiddenItemEventJSON();
OrderedJson::object buildSecretBaseEventJSON();
void setPixmapFromSpritesheet(QImage, int, int, bool);
int getPixelX();
int getPixelY();
QSet<QString> getExpectedFields();
void readCustomValues(QJsonObject values);
void addCustomValuesTo(OrderedJson::object *obj);
void setFrameFromMovement(QString);
QMap<QString, QString> values;
QMap<QString, QString> customValues;
QPixmap pixmap;
int spriteWidth;
int spriteHeight;
int frame = 0;
bool hFlip = false;
bool usingSprite;
DraggablePixmapItem *pixmapItem = nullptr;
void setPixmapItem(DraggablePixmapItem *item) { pixmapItem = item; }
};
#endif // EVENT_H

658
include/core/events.h Normal file
View file

@ -0,0 +1,658 @@
#pragma once
#ifndef EVENTS_H
#define EVENTS_H
#include <QString>
#include <QMap>
#include <QSet>
#include <QPixmap>
#include <QJsonObject>
#include "orderedjson.h"
using OrderedJson = poryjson::Json;
class Project;
class Map;
class EventFrame;
class ObjectFrame;
class CloneObjectFrame;
class WarpFrame;
class DraggablePixmapItem;
class Event;
class ObjectEvent;
class CloneObjectEvent;
class WarpEvent;
class CoordEvent;
class TriggerEvent;
class WeatherTriggerEvent;
class BgEvent;
class SignEvent;
class HiddenItemEvent;
class SecretBaseEvent;
class HealLocationEvent;
class EventVisitor {
public:
virtual void nothing() { }
virtual void visitObject(ObjectEvent *) = 0;
virtual void visitTrigger(TriggerEvent *) = 0;
virtual void visitSign(SignEvent *) = 0;
};
///
/// Event base class -- purely virtual
///
class Event {
public:
virtual ~Event();
// disable copy constructor
Event(const Event &other) = delete;
// disable assignment operator
Event& operator=(const Event &other) = delete;
protected:
Event() {
this->spriteWidth = 16;
this->spriteHeight = 16;
this->usingSprite = false;
}
// public enums & static methods
public:
enum class Type {
Object, CloneObject,
Warp,
Trigger, WeatherTrigger,
Sign, HiddenItem, SecretBase,
HealLocation,
Generic,
None,
};
enum class Group {
Object,
Warp,
Coord,
Bg,
Heal,
None,
};
// all event groups except warps have IDs that start at 1
static int getIndexOffset(Event::Group group) {
return (group == Event::Group::Warp) ? 0 : 1;
}
static Event::Group typeToGroup(Event::Type type) {
switch (type) {
case Event::Type::Object:
case Event::Type::CloneObject:
return Event::Group::Object;
case Event::Type::Warp:
return Event::Group::Warp;
case Event::Type::Trigger:
case Event::Type::WeatherTrigger:
return Event::Group::Coord;
case Event::Type::Sign:
case Event::Type::HiddenItem:
case Event::Type::SecretBase:
return Event::Group::Bg;
case Event::Type::HealLocation:
return Event::Group::Heal;
default:
return Event::Group::None;
}
}
// standard public methods
public:
virtual Event *duplicate() = 0;
void setMap(Map *newMap) { this->map = newMap; }
Map *getMap() const { return this->map; }
void modify();
virtual void accept(EventVisitor *) { }
void setX(int newX) { this->x = newX; }
void setY(int newY) { this->y = newY; }
void setZ(int newZ) { this->elevation = newZ; }
void setElevation(int newElevation) { this->elevation = newElevation; }
int getX() const { return this->x; }
int getY() const { return this->y; }
int getZ() const { return this->elevation; }
int getElevation() const { return this->elevation; }
int getPixelX() const { return (this->x * 16) - qMax(0, (this->spriteWidth - 16) / 2); }
int getPixelY() const { return (this->y * 16) - qMax(0, this->spriteHeight - 16); }
virtual EventFrame *getEventFrame();
virtual EventFrame *createEventFrame() = 0;
void destroyEventFrame();
Event::Group getEventGroup() const { return this->eventGroup; }
Event::Type getEventType() const { return this->eventType; }
virtual OrderedJson::object buildEventJson(Project *project) = 0;
virtual bool loadFromJson(QJsonObject json, Project *project) = 0;
virtual void setDefaultValues(Project *project);
virtual QSet<QString> getExpectedFields() = 0;
void readCustomValues(QJsonObject values);
void addCustomValuesTo(OrderedJson::object *obj);
QMap<QString, QString> getCustomValues() { return this->customValues; }
void setCustomValues(QMap<QString, QString> newCustomValues) { this->customValues = newCustomValues; }
virtual void loadPixmap(Project *project) = 0;
void setPixmap(QPixmap newPixmap) { this->pixmap = newPixmap; }
QPixmap getPixmap() { return this->pixmap; }
void setPixmapItem(DraggablePixmapItem *item);
DraggablePixmapItem *getPixmapItem() { return this->pixmapItem; }
void setUsingSprite(bool newUsingSprite) { this->usingSprite = newUsingSprite; }
bool getUsingSprite() const { return this->usingSprite; }
void setSpriteWidth(int newSpriteWidth) { this->spriteWidth = newSpriteWidth; }
int getspriteWidth() const { return this->spriteWidth; }
void setSpriteHeight(int newSpriteHeight) { this->spriteHeight = newSpriteHeight; }
int getspriteHeight() const { return this->spriteHeight; }
int getEventIndex();
static QString eventTypeToString(Event::Type type);
static Event::Type eventTypeFromString(QString type);
// protected attributes
protected:
Map *map = nullptr;
Type eventType = Event::Type::None;
Group eventGroup = Event::Group::None;
// could be private?
int x = 0;
int y = 0;
int elevation = 0;
int spriteWidth = 16;
int spriteHeight = 16;
bool usingSprite = false;
QMap<QString, QString> customValues;
QPixmap pixmap;
DraggablePixmapItem *pixmapItem = nullptr;
EventFrame *eventFrame = nullptr;
};
///
/// Object Event
///
class ObjectEvent : public Event {
public:
ObjectEvent() : Event() {
this->eventGroup = Event::Group::Object;
this->eventType = Event::Type::Object;
}
virtual ~ObjectEvent() {}
virtual Event *duplicate() override;
virtual void accept(EventVisitor *visitor) override { visitor->visitObject(this); }
virtual EventFrame *createEventFrame() override;
virtual OrderedJson::object buildEventJson(Project *project) override;
virtual bool loadFromJson(QJsonObject json, Project *project) override;
virtual void setDefaultValues(Project *project) override;
virtual QSet<QString> getExpectedFields() override;
virtual void loadPixmap(Project *project) override;
void setGfx(QString newGfx) { this->gfx = newGfx; }
QString getGfx() { return this->gfx; }
void setMovement(QString newMovement) { this->movement = newMovement; }
QString getMovement() { return this->movement; }
void setRadiusX(int newRadiusX) { this->radiusX = newRadiusX; }
int getRadiusX() { return this->radiusX; }
void setRadiusY(int newRadiusY) { this->radiusY = newRadiusY; }
int getRadiusY() { return this->radiusY; }
void setTrainerType(QString newTrainerType) { this->trainerType = newTrainerType; }
QString getTrainerType() { return this->trainerType; }
void setSightRadiusBerryTreeID(QString newValue) { this->sightRadiusBerryTreeID = newValue; }
QString getSightRadiusBerryTreeID() { return this->sightRadiusBerryTreeID; }
void setScript(QString newScript) { this->script = newScript; }
QString getScript() { return this->script; }
void setFlag(QString newFlag) { this->flag = newFlag; }
QString getFlag() { return this->flag; }
public:
void setFrameFromMovement(QString movement);
void setPixmapFromSpritesheet(QImage, int, int, bool);
protected:
QString gfx;
QString movement;
int radiusX = 0;
int radiusY = 0;
QString trainerType;
QString sightRadiusBerryTreeID;
QString script;
QString flag;
int frame = 0;
bool hFlip = false;
bool vFlip = false;
};
///
/// Clone Object Event
///
class CloneObjectEvent : public ObjectEvent {
public:
CloneObjectEvent() : ObjectEvent() {
this->eventGroup = Event::Group::Object;
this->eventType = Event::Type::CloneObject;
}
virtual ~CloneObjectEvent() {}
virtual Event *duplicate() override;
virtual EventFrame *createEventFrame() override;
virtual OrderedJson::object buildEventJson(Project *project) override;
virtual bool loadFromJson(QJsonObject json, Project *project) override;
virtual void setDefaultValues(Project *project) override;
virtual QSet<QString> getExpectedFields() override;
virtual void loadPixmap(Project *project) override;
void setTargetMap(QString newTargetMap) { this->targetMap = newTargetMap; }
QString getTargetMap() { return this->targetMap; }
void setTargetID(int newTargetID) { this->targetID = newTargetID; }
int getTargetID() { return this->targetID; }
private:
QString targetMap;
int targetID = 0;
};
///
/// Warp Event
///
class WarpEvent : public Event {
public:
WarpEvent() : Event() {
this->eventGroup = Event::Group::Warp;
this->eventType = Event::Type::Warp;
}
virtual ~WarpEvent() {}
virtual Event *duplicate() override;
virtual EventFrame *createEventFrame() override;
virtual OrderedJson::object buildEventJson(Project *project) override;
virtual bool loadFromJson(QJsonObject json, Project *project) override;
virtual void setDefaultValues(Project *project) override;
virtual QSet<QString> getExpectedFields() override;
virtual void loadPixmap(Project *) override;
void setDestinationMap(QString newDestinationMap) { this->destinationMap = newDestinationMap; }
QString getDestinationMap() { return this->destinationMap; }
void setDestinationWarpID(int newDestinationWarpID) { this->destinationWarpID = newDestinationWarpID; }
int getDestinationWarpID() { return this->destinationWarpID; }
private:
QString destinationMap;
int destinationWarpID = 0;
};
///
/// Coord Event
///
class CoordEvent : public Event {
public:
CoordEvent() : Event() {}
virtual ~CoordEvent() {}
virtual Event *duplicate() override = 0;
virtual EventFrame *createEventFrame() override = 0;
virtual OrderedJson::object buildEventJson(Project *project) override = 0;
virtual bool loadFromJson(QJsonObject json, Project *project) override = 0;
virtual void setDefaultValues(Project *project) override = 0;
virtual QSet<QString> getExpectedFields() override = 0;
virtual void loadPixmap(Project *) override;
};
///
/// Trigger Event
///
class TriggerEvent : public CoordEvent {
public:
TriggerEvent() : CoordEvent() {
this->eventGroup = Event::Group::Coord;
this->eventType = Event::Type::Trigger;
}
virtual ~TriggerEvent() {}
virtual Event *duplicate() override;
virtual void accept(EventVisitor *visitor) override { visitor->visitTrigger(this); }
virtual EventFrame *createEventFrame() override;
virtual OrderedJson::object buildEventJson(Project *project) override;
virtual bool loadFromJson(QJsonObject json, Project *project) override;
virtual void setDefaultValues(Project *project) override;
virtual QSet<QString> getExpectedFields() override;
void setScriptVar(QString newScriptVar) { this->scriptVar = newScriptVar; }
QString getScriptVar() { return this->scriptVar; }
void setScriptVarValue(QString newScriptVarValue) { this->scriptVarValue = newScriptVarValue; }
QString getScriptVarValue() { return this->scriptVarValue; }
void setScriptLabel(QString newScriptLabel) { this->scriptLabel = newScriptLabel; }
QString getScriptLabel() { return this->scriptLabel; }
private:
QString scriptVar;
QString scriptVarValue;
QString scriptLabel;
};
///
/// Weather Trigger Event
///
class WeatherTriggerEvent : public CoordEvent {
public:
WeatherTriggerEvent() : CoordEvent() {
this->eventGroup = Event::Group::Coord;
this->eventType = Event::Type::WeatherTrigger;
}
virtual ~WeatherTriggerEvent() {}
virtual Event *duplicate() override;
virtual EventFrame *createEventFrame() override;
virtual OrderedJson::object buildEventJson(Project *project) override;
virtual bool loadFromJson(QJsonObject json, Project *project) override;
virtual void setDefaultValues(Project *project) override;
virtual QSet<QString> getExpectedFields() override;
void setWeather(QString newWeather) { this->weather = newWeather; }
QString getWeather() { return this->weather; }
private:
QString weather;
};
///
/// BG Event
///
class BGEvent : public Event {
public:
BGEvent() : Event() {
this->eventGroup = Event::Group::Bg;
}
virtual ~BGEvent() {}
virtual Event *duplicate() override = 0;
virtual EventFrame *createEventFrame() override = 0;
virtual OrderedJson::object buildEventJson(Project *project) override = 0;
virtual bool loadFromJson(QJsonObject json, Project *project) override = 0;
virtual void setDefaultValues(Project *project) override = 0;
virtual QSet<QString> getExpectedFields() override = 0;
virtual void loadPixmap(Project *project) override;
};
///
/// Sign Event
///
class SignEvent : public BGEvent {
public:
SignEvent() : BGEvent() {
this->eventType = Event::Type::Sign;
}
virtual ~SignEvent() {}
virtual Event *duplicate() override;
virtual void accept(EventVisitor *visitor) override { visitor->visitSign(this); }
virtual EventFrame *createEventFrame() override;
virtual OrderedJson::object buildEventJson(Project *project) override;
virtual bool loadFromJson(QJsonObject json, Project *project) override;
virtual void setDefaultValues(Project *project) override;
virtual QSet<QString> getExpectedFields() override;
void setFacingDirection(QString newFacingDirection) { this->facingDirection = newFacingDirection; }
QString getFacingDirection() { return this->facingDirection; }
void setScriptLabel(QString newScriptLabel) { this->scriptLabel = newScriptLabel; }
QString getScriptLabel() { return this->scriptLabel; }
private:
QString facingDirection;
QString scriptLabel;
};
///
/// Hidden Item Event
///
class HiddenItemEvent : public BGEvent {
public:
HiddenItemEvent() : BGEvent() {
this->eventType = Event::Type::HiddenItem;
}
virtual ~HiddenItemEvent() {}
virtual Event *duplicate() override;
virtual EventFrame *createEventFrame() override;
virtual OrderedJson::object buildEventJson(Project *project) override;
virtual bool loadFromJson(QJsonObject json, Project *project) override;
virtual void setDefaultValues(Project *project) override;
virtual QSet<QString> getExpectedFields() override;
void setItem(QString newItem) { this->item = newItem; }
QString getItem() { return this->item; }
void setFlag(QString newFlag) { this->flag = newFlag; }
QString getFlag() { return this->flag; }
void setQuantity(int newQuantity) { this->quantity = newQuantity; }
int getQuantity() { return this->quantity; }
void setUnderfoot(bool newUnderfoot) { this->underfoot = newUnderfoot; }
bool getUnderfoot() { return this->underfoot; }
private:
QString item;
QString flag;
// optional
int quantity = 0;
bool underfoot = false;
};
///
/// Secret Base Event
///
class SecretBaseEvent : public BGEvent {
public:
SecretBaseEvent() : BGEvent() {
this->eventType = Event::Type::SecretBase;
}
virtual ~SecretBaseEvent() {}
virtual Event *duplicate() override;
virtual EventFrame *createEventFrame() override;
virtual OrderedJson::object buildEventJson(Project *project) override;
virtual bool loadFromJson(QJsonObject json, Project *project) override;
virtual void setDefaultValues(Project *project) override;
virtual QSet<QString> getExpectedFields() override;
void setBaseID(QString newBaseID) { this->baseID = newBaseID; }
QString getBaseID() { return this->baseID; }
private:
QString baseID;
};
///
/// Heal Location Event
///
class HealLocationEvent : public Event {
public:
HealLocationEvent() : Event() {
this->eventGroup = Event::Group::Heal;
this->eventType = Event::Type::HealLocation;
}
virtual ~HealLocationEvent() {}
virtual Event *duplicate() override { return nullptr; }
virtual EventFrame *createEventFrame() override;
virtual OrderedJson::object buildEventJson(Project *project) override;
virtual bool loadFromJson(QJsonObject, Project *) override { return false; }
virtual void setDefaultValues(Project *project) override;
virtual QSet<QString> getExpectedFields() override { return QSet<QString>(); }
virtual void loadPixmap(Project *project) override;
void setIndex(int newIndex) { this->index = newIndex; }
int getIndex() { return this->index; }
void setLocationName(QString newLocationName) { this->locationName = newLocationName; }
QString getLocationName() { return this->locationName; }
void setIdName(QString newIdName) { this->idName = newIdName; }
QString getIdName() { return this->idName; }
void setRespawnMap(QString newRespawnMap) { this->respawnMap = newRespawnMap; }
QString getRespawnMap() { return this->respawnMap; }
void setRespawnNPC(uint16_t newRespawnNPC) { this->respawnNPC = newRespawnNPC; }
uint16_t getRespawnNPC() { return this->respawnNPC; }
private:
int index = -1;
QString locationName;
QString idName;
QString respawnMap;
uint16_t respawnNPC = 0;
};
///
/// Keeps track of scripts
///
class ScriptTracker : public EventVisitor {
public:
virtual void visitObject(ObjectEvent *object) override { this->scripts << object->getScript(); };
virtual void visitTrigger(TriggerEvent *trigger) override { this->scripts << trigger->getScriptLabel(); };
virtual void visitSign(SignEvent *sign) override { this->scripts << sign->getScriptLabel(); };
QStringList getScripts() { return this->scripts; }
private:
QStringList scripts;
};
#endif // EVENTS_H

View file

@ -2,10 +2,11 @@
#ifndef HEALLOCATION_H
#define HEALLOCATION_H
#include "event.h"
#include <QString>
#include <QDebug>
class Event;
class HealLocation {
public:
@ -21,7 +22,7 @@ public:
uint16_t y;
QString respawnMap;
uint16_t respawnNPC;
static HealLocation fromEvent(Event*);
static HealLocation fromEvent(Event *);
};
#endif // HEALLOCATION_H

View file

@ -6,7 +6,7 @@
#include "mapconnection.h"
#include "maplayout.h"
#include "tileset.h"
#include "event.h"
#include "events.h"
#include <QUndoStack>
#include <QPixmap>
@ -63,7 +63,10 @@ public:
QPixmap collision_pixmap;
QImage image;
QPixmap pixmap;
QMap<QString, QList<Event*>> events;
QMap<Event::Group, QList<Event *>> events;
QList<Event *> ownedEvents; // for memory management
QList<MapConnection*> connections;
QList<int> metatileLayerOrder;
QList<float> metatileLayerOpacity;
@ -92,10 +95,10 @@ public:
void floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
void _floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
void magicFillCollisionElevation(int x, int y, uint16_t collision, uint16_t elevation);
QList<Event*> getAllEvents() const;
QStringList eventScriptLabels(const QString &event_group_type = QString()) const;
void removeEvent(Event*);
void addEvent(Event*);
QList<Event *> getAllEvents() const;
QStringList eventScriptLabels(Event::Group group = Event::Group::None) const;
void removeEvent(Event *);
void addEvent(Event *);
QPixmap renderConnection(MapConnection, MapLayout *);
QPixmap renderBorder(bool ignoreCache = false);
void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true, bool enableScriptCallback = false);
@ -104,9 +107,7 @@ public:
bool hasUnsavedChanges();
bool isWithinBounds(int x, int y);
bool isWithinBorderBounds(int x, int y);
// for memory management
QVector<Event *> ownedEvents;
void openScript(QString label);
MapPixmapItem *mapItem = nullptr;
void setMapItem(MapPixmapItem *item) { mapItem = item; }
@ -118,6 +119,8 @@ public:
void setBorderItem(BorderMetatilesPixmapItem *item) { borderItem = item; }
QUndoStack editHistory;
void modify();
void clean();
private:
void setNewDimensionsBlockdata(int newWidth, int newHeight);
@ -125,8 +128,10 @@ private:
signals:
void mapChanged(Map *map);
void modified();
void mapDimensionsChanged(const QSize &size);
void mapNeedsRedrawing();
void openScriptRequested(QString label);
};
#endif // MAP_H

View file

@ -4,6 +4,7 @@
#include "heallocation.h"
#include "log.h"
#include "orderedjson.h"
#include <QString>
#include <QList>

View file

@ -158,7 +158,7 @@ public:
void undo() override;
void redo() override;
bool mergeWith(const QUndoCommand *command) override { return false; }
bool mergeWith(const QUndoCommand *) override { return false; }
int id() const override { return RMCommandId::ID_ClearEntries; }
private:

View file

@ -96,8 +96,7 @@ public:
DraggablePixmapItem *addMapEvent(Event *event);
void selectMapEvent(DraggablePixmapItem *object);
void selectMapEvent(DraggablePixmapItem *object, bool toggle);
DraggablePixmapItem *addNewEvent(QString event_type);
void deleteEvent(Event *);
DraggablePixmapItem *addNewEvent(Event::Type type);
void updateSelectedEvents();
void duplicateSelectedEvents();
void redrawObject(DraggablePixmapItem *item);
@ -105,6 +104,8 @@ public:
void updateCursorRectPos(int x, int y);
void setCursorRectVisible(bool visible);
bool eventLimitReached(Map *, Event::Type);
QGraphicsScene *scene = nullptr;
QGraphicsPixmapItem *current_view = nullptr;
MapPixmapItem *map_item = nullptr;
@ -131,8 +132,7 @@ public:
CurrentSelectedMetatilesPixmapItem *current_metatile_selection_item = nullptr;
MovementPermissionsSelector *movement_permissions_selector_item = nullptr;
QList<DraggablePixmapItem*> *events = nullptr;
QList<DraggablePixmapItem*> *selected_events = nullptr;
QList<DraggablePixmapItem *> *selected_events = nullptr;
QString map_edit_mode = "paint";
QString obj_edit_mode = "select";
@ -151,7 +151,7 @@ public:
void shouldReselectEvents();
void scaleMapView(int);
void openInTextEditor(const QString &path, int lineNum = 0) const;
bool eventLimitReached(QString event_type);
bool eventLimitReached(Event::Type type);
public slots:
void openMapScripts() const;
@ -159,6 +159,7 @@ public slots:
void openProjectInTextEditor() const;
void maskNonVisibleConnectionTiles();
void onBorderMetatilesChanged();
void selectedEventIndexChanged(int index, Event::Group eventGroup);
private:
void setConnectionItemsVisible(bool);
@ -207,10 +208,9 @@ private slots:
signals:
void objectsChanged();
void selectedObjectsChanged();
void loadMapRequested(QString, QString);
void wildMonDataChanged();
void warpEventDoubleClicked(QString, QString, QString);
void warpEventDoubleClicked(QString, int, Event::Group);
void currentMetatilesSelectionChanged();
void mapRulerStatusChanged(const QString &);
void editedMapData();

View file

@ -26,6 +26,8 @@
#include "shortcutseditor.h"
#include "preferenceeditor.h"
namespace Ui {
class MainWindow;
}
@ -78,10 +80,10 @@ public:
Q_INVOKABLE void setBorderHeight(int height);
void refreshAfterPaletteChange(Tileset *tileset);
void setTilesetPalette(Tileset *tileset, int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setPrimaryTilesetPalette(int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setPrimaryTilesetPalettes(QList<QList<QList<int>>> palettes);
Q_INVOKABLE void setSecondaryTilesetPalette(int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setSecondaryTilesetPalettes(QList<QList<QList<int>>> palettes);
Q_INVOKABLE void setPrimaryTilesetPalette(int paletteIndex, QList<QList<int>> colors, bool forceRedraw = true);
Q_INVOKABLE void setPrimaryTilesetPalettes(QList<QList<QList<int>>> palettes, bool forceRedraw = true);
Q_INVOKABLE void setSecondaryTilesetPalette(int paletteIndex, QList<QList<int>> colors, bool forceRedraw = true);
Q_INVOKABLE void setSecondaryTilesetPalettes(QList<QList<QList<int>>> palettes, bool forceRedraw = true);
QJSValue getTilesetPalette(const QList<QList<QRgb>> &palettes, int paletteIndex);
QJSValue getTilesetPalettes(const QList<QList<QRgb>> &palettes);
Q_INVOKABLE QJSValue getPrimaryTilesetPalette(int paletteIndex);
@ -90,10 +92,10 @@ public:
Q_INVOKABLE QJSValue getSecondaryTilesetPalettes();
void refreshAfterPalettePreviewChange();
void setTilesetPalettePreview(Tileset *tileset, int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setPrimaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setPrimaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes);
Q_INVOKABLE void setSecondaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors);
Q_INVOKABLE void setSecondaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes);
Q_INVOKABLE void setPrimaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors, bool forceRedraw = true);
Q_INVOKABLE void setPrimaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes, bool forceRedraw = true);
Q_INVOKABLE void setSecondaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors, bool forceRedraw = true);
Q_INVOKABLE void setSecondaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes, bool forceRedraw = true);
Q_INVOKABLE QJSValue getPrimaryTilesetPalettePreview(int paletteIndex);
Q_INVOKABLE QJSValue getPrimaryTilesetPalettesPreview();
Q_INVOKABLE QJSValue getSecondaryTilesetPalettePreview(int paletteIndex);
@ -161,7 +163,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 event_id, QString event_group);
void openWarpMap(QString map_name, int event_id, Event::Group event_group);
void duplicate();
void setClipboardData(poryjson::Json::object);
@ -216,7 +218,8 @@ private slots:
void on_toolButton_deleteObject_clicked();
void addNewEvent(QString);
void addNewEvent(Event::Type type);
void displayEventTabs();
void updateSelectedObjects();
void updateObjects();
@ -265,8 +268,6 @@ private slots:
void eventTabChanged(int index);
void selectedEventIndexChanged(int index);
void on_horizontalSlider_CollisionTransparency_valueChanged(int value);
void on_toolButton_ExpandAll_clicked();
void on_toolButton_CollapseAll_clicked();
@ -325,8 +326,6 @@ private:
DraggablePixmapItem *selectedBG;
DraggablePixmapItem *selectedHealspot;
QVector<QToolButton *> openScriptButtons;
bool isProgrammaticEventTabChange;
bool projectHasUnsavedChanges;
bool projectOpenFailure = false;
@ -374,7 +373,7 @@ private:
void setTheme(QString);
bool openRecentProject();
void updateTilesetEditor();
QString getEventGroupFromTabWidget(QWidget *tab);
Event::Group getEventGroupFromTabWidget(QWidget *tab);
void closeSupplementaryWindows();
void setWindowDisabled(bool);

View file

@ -5,7 +5,6 @@
#include "map.h"
#include "blockdata.h"
#include "heallocation.h"
#include "event.h"
#include "wildmoninfo.h"
#include "parseutil.h"
#include "orderedjson.h"
@ -83,6 +82,8 @@ public:
QMap<QString, qint64> modifiedFileTimestamps;
bool usingAsmTilesets;
const QPixmap entitiesPixmap = QPixmap(":/images/Entities_16x16.png");
void set_root(QString);
void initSignals();
@ -194,7 +195,7 @@ public:
bool readEventGraphics();
QMap<QString, QMap<QString, QString>> readObjEventGfxInfo();
void setEventPixmap(Event * event, bool forceLoad = false);
void setEventPixmap(Event *event, bool forceLoad = false);
QString fixPalettePath(QString path);
QString fixGraphicPath(QString path);
@ -204,6 +205,7 @@ public:
QString getMapScriptsFilePath(const QString &mapName) const;
QStringList getEventScriptsFilePaths() const;
QCompleter *getEventScriptLabelCompleter(QStringList additionalScriptLabels);
QStringList getGlobalScriptLabels();
void saveMapHealEvents(Map *map);

View file

@ -1,7 +1,7 @@
#ifndef CUSTOMATTRIBUTESTABLE_H
#define CUSTOMATTRIBUTESTABLE_H
#include "event.h"
#include "events.h"
#include <QObject>
#include <QFrame>
#include <QTableWidget>

View file

@ -8,7 +8,7 @@
#include <QtWidgets>
#include "event.h"
#include "events.h"
class Editor;
@ -17,10 +17,10 @@ class DraggablePixmapItem : public QObject, public QGraphicsPixmapItem {
public:
DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {}
DraggablePixmapItem(Event *event_, Editor *editor_) : QGraphicsPixmapItem(event_->pixmap) {
event = event_;
DraggablePixmapItem(Event *event, Editor *editor) : QGraphicsPixmapItem(event->getPixmap()) {
this->event = event;
event->setPixmapItem(this);
editor = editor_;
this->editor = editor;
updatePosition();
}
@ -37,8 +37,6 @@ public:
void moveTo(const QPoint &pos);
void emitPositionChanged();
void updatePixmap();
void bind(QComboBox *combo, QString key);
void bindToUserData(QComboBox *combo, QString key);
signals:
void positionChanged(Event *event);
@ -49,25 +47,18 @@ signals:
void onPropertyChanged(QString key, QString value);
public slots:
void set_x(const QString &text) {
event->put("x", text);
void set_x(int x) {
event->setX(x);
updatePosition();
}
void set_y(const QString &text) {
event->put("y", text);
void set_y(int y) {
event->setY(y);
updatePosition();
}
void set_elevation(const QString &text) {
event->put("elevation", text);
void set_elevation(int z) {
event->setElevation(z);
updatePosition();
}
void set_sprite(const QString &text) {
event->put("sprite", text);
updatePixmap();
}
void set_script(const QString &text) {
event->put("script_label", text);
}
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);

291
include/ui/eventframes.h Normal file
View file

@ -0,0 +1,291 @@
#pragma once
#ifndef EVENTRAMES_H
#define EVENTRAMES_H
#include <QtWidgets>
#include "noscrollspinbox.h"
#include "noscrollcombobox.h"
#include "events.h"
class Project;
class EventFrame : public QFrame {
Q_OBJECT
public:
EventFrame(Event *event, QWidget *parent = nullptr)
: QFrame(parent), event(event) { }
virtual void setup();
void initCustomAttributesTable();
virtual void connectSignals();
virtual void initialize();
virtual void populate(Project *project);
void invalidateConnections();
void invalidateUi();
void invalidateValues();
virtual void setActive(bool active);
public:
QLabel *label_id;
QVBoxLayout *layout_main;
QSpinBox *spinner_id;
NoScrollSpinBox *spinner_x;
NoScrollSpinBox *spinner_y;
NoScrollSpinBox *spinner_z;
QLabel *hideable_label_z;
QLabel *label_icon;
QFrame *frame_contents;
QVBoxLayout *layout_contents;
protected:
bool populated = false;
bool initialized = false;
bool connected = false;
private:
Event *event;
};
class ObjectFrame : public EventFrame {
Q_OBJECT
public:
ObjectFrame(ObjectEvent *object, QWidget *parent = nullptr)
: EventFrame(object, parent), object(object) {}
virtual ~ObjectFrame() {
delete this->scriptCompleter;
}
virtual void setup() override;
virtual void initialize() override;
virtual void connectSignals() override;
virtual void populate(Project *project) override;
public:
NoScrollComboBox *combo_sprite;
NoScrollComboBox *combo_movement;
NoScrollSpinBox *spinner_radius_x;
NoScrollSpinBox *spinner_radius_y;
NoScrollComboBox *combo_script;
QToolButton *button_script;
NoScrollComboBox *combo_flag;
NoScrollComboBox *combo_trainer_type;
NoScrollComboBox *combo_radius_treeid;
QCheckBox *check_in_connection;
private:
ObjectEvent *object;
QCompleter *scriptCompleter = nullptr;
};
class CloneObjectFrame : public EventFrame {
Q_OBJECT
public:
CloneObjectFrame(CloneObjectEvent *clone, QWidget *parent = nullptr)
: EventFrame(clone, parent), clone(clone) {}
virtual void setup() override;
virtual void initialize() override;
virtual void connectSignals() override;
virtual void populate(Project *project) override;
public:
NoScrollComboBox *combo_sprite;
NoScrollSpinBox *spinner_target_id;
NoScrollComboBox *combo_target_map;
private:
CloneObjectEvent *clone;
};
class WarpFrame : public EventFrame {
Q_OBJECT
public:
WarpFrame(WarpEvent *warp, QWidget *parent = nullptr)
: EventFrame(warp, parent), warp(warp) {}
virtual void setup() override;
virtual void initialize() override;
virtual void connectSignals() override;
virtual void populate(Project *project) override;
public:
NoScrollComboBox *combo_dest_map;
NoScrollSpinBox *spinner_dest_warp;
private:
WarpEvent *warp;
};
class TriggerFrame : public EventFrame {
Q_OBJECT
public:
TriggerFrame(TriggerEvent *trigger, QWidget *parent = nullptr)
: EventFrame(trigger, parent), trigger(trigger) {}
virtual ~TriggerFrame() {
delete this->scriptCompleter;
}
virtual void setup() override;
virtual void initialize() override;
virtual void connectSignals() override;
virtual void populate(Project *project) override;
public:
NoScrollComboBox *combo_script;
NoScrollComboBox *combo_var;
NoScrollComboBox *combo_var_value;
private:
TriggerEvent *trigger;
QCompleter *scriptCompleter = nullptr;
};
class WeatherTriggerFrame : public EventFrame {
Q_OBJECT
public:
WeatherTriggerFrame(WeatherTriggerEvent *weatherTrigger, QWidget *parent = nullptr)
: EventFrame(weatherTrigger, parent), weatherTrigger(weatherTrigger) {}
virtual void setup() override;
virtual void initialize() override;
virtual void connectSignals() override;
virtual void populate(Project *project) override;
public:
NoScrollComboBox *combo_weather;
private:
WeatherTriggerEvent *weatherTrigger;
};
class SignFrame : public EventFrame {
Q_OBJECT
public:
SignFrame(SignEvent *sign, QWidget *parent = nullptr)
: EventFrame(sign, parent), sign(sign) {}
virtual ~SignFrame() {
delete this->scriptCompleter;
}
virtual void setup() override;
virtual void initialize() override;
virtual void connectSignals() override;
virtual void populate(Project *project) override;
public:
NoScrollComboBox *combo_facing_dir;
NoScrollComboBox *combo_script;
private:
SignEvent *sign;
QCompleter *scriptCompleter = nullptr;
};
class HiddenItemFrame : public EventFrame {
Q_OBJECT
public:
HiddenItemFrame(HiddenItemEvent *hiddenItem, QWidget *parent = nullptr)
: EventFrame(hiddenItem, parent), hiddenItem(hiddenItem) {}
virtual void setup() override;
virtual void initialize() override;
virtual void connectSignals() override;
virtual void populate(Project *project) override;
public:
QFrame *hideable_quantity;
QFrame *hideable_itemfinder;
NoScrollComboBox *combo_item;
NoScrollComboBox *combo_flag;
NoScrollSpinBox *spinner_quantity;
QCheckBox *check_itemfinder;
private:
HiddenItemEvent *hiddenItem;
};
class SecretBaseFrame : public EventFrame {
Q_OBJECT
public:
SecretBaseFrame(SecretBaseEvent *secretBase, QWidget *parent = nullptr)
: EventFrame(secretBase, parent), secretBase(secretBase) {}
virtual void setup() override;
virtual void initialize() override;
virtual void connectSignals() override;
virtual void populate(Project *project) override;
public:
NoScrollComboBox *combo_base_id;
private:
SecretBaseEvent *secretBase;
};
class HealLocationFrame : public EventFrame {
Q_OBJECT
public:
HealLocationFrame(HealLocationEvent *healLocation, QWidget *parent = nullptr)
: EventFrame(healLocation, parent), healLocation(healLocation) {}
virtual void setup() override;
virtual void initialize() override;
virtual void connectSignals() override;
virtual void populate(Project *project) override;
public:
QFrame *hideable_respawn_map;
QFrame *hideable_respawn_npc;
NoScrollComboBox *combo_respawn_map;
NoScrollSpinBox *spinner_respawn_npc;
private:
HealLocationEvent *healLocation;
};
#endif // EVENTRAMES_H

View file

@ -1,29 +0,0 @@
#ifndef EVENTPROPERTIESFRAME_H
#define EVENTPROPERTIESFRAME_H
#include "event.h"
#include <QFrame>
namespace Ui {
class EventPropertiesFrame;
}
class EventPropertiesFrame : public QFrame
{
Q_OBJECT
public:
explicit EventPropertiesFrame(Event *event, QWidget *parent = nullptr);
~EventPropertiesFrame();
void paintEvent(QPaintEvent*);
public:
Ui::EventPropertiesFrame *ui;
private:
Event *event;
bool firstShow = true;
};
#endif // EVENTPROPERTIESFRAME_H

View file

@ -44,9 +44,21 @@ public:
Q_INVOKABLE int getOpacity(int layer = 0);
Q_INVOKABLE void setOpacity(int opacity, int layer);
Q_INVOKABLE void setOpacity(int opacity);
Q_INVOKABLE qreal getHorizontalScale(int layer = 0);
Q_INVOKABLE qreal getVerticalScale(int layer = 0);
Q_INVOKABLE void setHorizontalScale(qreal scale, int layer);
Q_INVOKABLE void setHorizontalScale(qreal scale);
Q_INVOKABLE void setVerticalScale(qreal scale, int layer);
Q_INVOKABLE void setVerticalScale(qreal scale);
Q_INVOKABLE int getRotation(int layer = 0);
Q_INVOKABLE void setRotation(int angle, int layer);
Q_INVOKABLE void setRotation(int angle);
Q_INVOKABLE void rotate(int degrees, int layer);
Q_INVOKABLE void rotate(int degrees);
Q_INVOKABLE void addText(QString text, int x, int y, QString color = "#000000", int fontSize = 12, int layer = 0);
Q_INVOKABLE void addRect(int x, int y, int width, int height, QString color = "#000000", int layer = 0);
Q_INVOKABLE void addFilledRect(int x, int y, int width, int height, QString color = "#000000", int layer = 0);
Q_INVOKABLE void addRect(int x, int y, int width, int height, QString borderColor = "#000000", QString fillColor = "transparent", int rounding = 0, int layer = 0);
Q_INVOKABLE void addPath(QList<QList<int>> coords, QString borderColor = "#000000", QString fillColor = "transparent", int layer = 0);
Q_INVOKABLE void addPath(QList<int> xCoords, QList<int> yCoords, QString borderColor = "#000000", QString fillColor = "transparent", int layer = 0);
Q_INVOKABLE void addImage(int x, int y, QString filepath, int layer = 0, bool useCache = true);
Q_INVOKABLE void createImage(int x, int y, QString filepath,
int width = -1, int height = -1, int xOffset = 0, int yOffset = 0,

View file

@ -1,7 +1,7 @@
#ifndef NEWEVENTTOOLBUTTON_H
#define NEWEVENTTOOLBUTTON_H
#include "event.h"
#include "events.h"
#include <QToolButton>
class NewEventToolButton : public QToolButton
@ -9,7 +9,7 @@ class NewEventToolButton : public QToolButton
Q_OBJECT
public:
explicit NewEventToolButton(QWidget *parent = nullptr);
QString getSelectedEventType();
Event::Type getSelectedEventType();
QAction *newObjectAction;
QAction *newCloneObjectAction;
QAction *newWarpAction;
@ -30,9 +30,9 @@ public slots:
void newHiddenItem();
void newSecretBase();
signals:
void newEventAdded(QString);
void newEventAdded(Event::Type);
private:
QString selectedEventType;
Event::Type selectedEventType;
void init();
};

View file

@ -6,12 +6,13 @@
#include <QColor>
#include <QPainter>
#include <QStaticText>
#include <QPainterPath>
class OverlayItem {
public:
OverlayItem() {}
virtual ~OverlayItem() {};
virtual void render(QPainter *, int, int) {};
virtual void render(QPainter *) {};
};
class OverlayText : public OverlayItem {
@ -25,7 +26,7 @@ public:
this->fontSize = fontSize;
}
~OverlayText() {}
virtual void render(QPainter *painter, int x, int y);
virtual void render(QPainter *painter);
private:
const QStaticText text;
int x;
@ -34,25 +35,19 @@ private:
int fontSize;
};
class OverlayRect : public OverlayItem {
class OverlayPath : public OverlayItem {
public:
OverlayRect(int x, int y, int width, int height, QColor color, bool filled) {
this->x = x;
this->y = y;
this->width = width;
this->height = height;
this->color = color;
this->filled = filled;
OverlayPath(QPainterPath path, QColor borderColor, QColor fillColor) {
this->path = path;
this->borderColor = borderColor;
this->fillColor = fillColor;
}
~OverlayRect() {}
virtual void render(QPainter *painter, int x, int y);
~OverlayPath() {}
virtual void render(QPainter *painter);
private:
int x;
int y;
int width;
int height;
QColor color;
bool filled;
QPainterPath path;
QColor borderColor;
QColor fillColor;
};
class OverlayImage : public OverlayItem {
@ -63,7 +58,7 @@ public:
this->image = image;
}
~OverlayImage() {}
virtual void render(QPainter *painter, int x, int y);
virtual void render(QPainter *painter);
private:
int x;
int y;
@ -76,6 +71,9 @@ public:
Overlay() {
this->x = 0;
this->y = 0;
this->angle = 0;
this->hScale = 1.0;
this->vScale = 1.0;
this->hidden = false;
this->opacity = 1.0;
this->clippingRect = nullptr;
@ -91,6 +89,13 @@ public:
int getY();
void setX(int x);
void setY(int y);
qreal getHScale();
qreal getVScale();
void setHScale(qreal scale);
void setVScale(qreal scale);
int getRotation();
void setRotation(int angle);
void rotate(int degrees);
void setClippingRect(QRectF rect);
void clearClippingRect();
void setPosition(int x, int y);
@ -98,14 +103,20 @@ public:
void renderItems(QPainter *painter);
QList<OverlayItem*> getItems();
void clearItems();
void addText(const QString text, int x, int y, QString color = "#000000", int fontSize = 12);
void addRect(int x, int y, int width, int height, QString color = "#000000", bool filled = false);
void addText(const QString text, int x, int y, QString colorStr, int fontSize);
bool addRect(int x, int y, int width, int height, QString borderColorStr, QString fillColorStr, int rounding);
bool addImage(int x, int y, QString filepath, bool useCache = true, int width = -1, int height = -1, int xOffset = 0, int yOffset = 0, qreal hScale = 1, qreal vScale = 1, QList<QRgb> palette = QList<QRgb>(), bool setTransparency = false);
bool addImage(int x, int y, QImage image);
bool addPath(QList<int> xCoords, QList<int> yCoords, QString borderColorStr, QString fillColorStr);
private:
void clampAngle();
QColor getColor(QString colorStr);
QList<OverlayItem*> items;
int x;
int y;
int angle;
qreal hScale;
qreal vScale;
bool hidden;
qreal opacity;
QRectF *clippingRect;

View file

@ -17,7 +17,7 @@ QMAKE_TARGET_BUNDLE_PREFIX = com.pret
SOURCES += src/core/block.cpp \
src/core/blockdata.cpp \
src/core/event.cpp \
src/core/events.cpp \
src/core/heallocation.cpp \
src/core/imageexport.cpp \
src/core/map.cpp \
@ -53,7 +53,7 @@ SOURCES += src/core/block.cpp \
src/ui/regionmapentriespixmapitem.cpp \
src/ui/cursortilerect.cpp \
src/ui/customattributestable.cpp \
src/ui/eventpropertiesframe.cpp \
src/ui/eventframes.cpp \
src/ui/filterchildrenproxymodel.cpp \
src/ui/graphicsview.cpp \
src/ui/imageproviders.cpp \
@ -99,7 +99,7 @@ SOURCES += src/core/block.cpp \
HEADERS += include/core/block.h \
include/core/blockdata.h \
include/core/event.h \
include/core/events.h \
include/core/heallocation.h \
include/core/history.h \
include/core/imageexport.h \
@ -136,7 +136,7 @@ HEADERS += include/core/block.h \
include/ui/regionmapentriespixmapitem.h \
include/ui/cursortilerect.h \
include/ui/customattributestable.h \
include/ui/eventpropertiesframe.h \
include/ui/eventframes.h \
include/ui/filterchildrenproxymodel.h \
include/ui/graphicsview.h \
include/ui/imageproviders.h \
@ -185,7 +185,6 @@ HEADERS += include/core/block.h \
include/log.h
FORMS += forms/mainwindow.ui \
forms/eventpropertiesframe.ui \
forms/prefabcreationdialog.ui \
forms/prefabframe.ui \
forms/tileseteditor.ui \
@ -209,5 +208,6 @@ INCLUDEPATH += include
INCLUDEPATH += include/core
INCLUDEPATH += include/ui
INCLUDEPATH += include/lib
INCLUDEPATH += forms
include(src/vendor/QtGifImage/gifimage/qtgifimage.pri)

View file

@ -9,16 +9,16 @@
int getEventTypeMask(QList<Event *> events) {
int eventTypeMask = 0;
for (auto event : events) {
QString groupType = event->get("event_group_type");
if (groupType == EventGroup::Object) {
Event::Group groupType = event->getEventGroup();
if (groupType == Event::Group::Object) {
eventTypeMask |= IDMask_EventType_Object;
} else if (groupType == EventGroup::Warp) {
} else if (groupType == Event::Group::Warp) {
eventTypeMask |= IDMask_EventType_Warp;
} else if (groupType == EventGroup::Coord) {
} else if (groupType == Event::Group::Coord) {
eventTypeMask |= IDMask_EventType_Trigger;
} else if (groupType == EventGroup::Bg) {
} else if (groupType == Event::Group::Bg) {
eventTypeMask |= IDMask_EventType_BG;
} else if (groupType == EventGroup::Heal) {
} else if (groupType == Event::Group::Heal) {
eventTypeMask |= IDMask_EventType_Heal;
}
}
@ -261,13 +261,13 @@ void EventMove::redo() {
QUndoCommand::redo();
for (Event *event : events) {
event->pixmapItem->move(deltaX, deltaY);
event->getPixmapItem()->move(deltaX, deltaY);
}
}
void EventMove::undo() {
for (Event *event : events) {
event->pixmapItem->move(-deltaX, -deltaY);
event->getPixmapItem()->move(-deltaX, -deltaY);
}
QUndoCommand::undo();
@ -331,16 +331,16 @@ void EventCreate::redo() {
// select this event
editor->selected_events->clear();
editor->selectMapEvent(event->pixmapItem, false);
editor->selectMapEvent(event->getPixmapItem(), false);
}
void EventCreate::undo() {
map->removeEvent(event);
if (editor->scene->items().contains(event->pixmapItem)) {
editor->scene->removeItem(event->pixmapItem);
if (editor->scene->items().contains(event->getPixmapItem())) {
editor->scene->removeItem(event->getPixmapItem());
}
editor->selected_events->removeOne(event->pixmapItem);
editor->selected_events->removeOne(event->getPixmapItem());
editor->shouldReselectEvents();
@ -377,15 +377,15 @@ void EventDelete::redo() {
for (Event *event : selectedEvents) {
map->removeEvent(event);
if (editor->scene->items().contains(event->pixmapItem)) {
editor->scene->removeItem(event->pixmapItem);
if (editor->scene->items().contains(event->getPixmapItem())) {
editor->scene->removeItem(event->getPixmapItem());
}
editor->selected_events->removeOne(event->pixmapItem);
editor->selected_events->removeOne(event->getPixmapItem());
}
editor->selected_events->clear();
if (nextSelectedEvent)
editor->selected_events->append(nextSelectedEvent->pixmapItem);
editor->selected_events->append(nextSelectedEvent->getPixmapItem());
editor->shouldReselectEvents();
}
@ -399,7 +399,7 @@ void EventDelete::undo() {
// select these events
editor->selected_events->clear();
for (Event *event : selectedEvents) {
editor->selected_events->append(event->pixmapItem);
editor->selected_events->append(event->getPixmapItem());
}
editor->shouldReselectEvents();
@ -441,7 +441,7 @@ void EventDuplicate::redo() {
// select these events
editor->selected_events->clear();
for (Event *event : selectedEvents) {
editor->selected_events->append(event->pixmapItem);
editor->selected_events->append(event->getPixmapItem());
}
editor->shouldReselectEvents();
}
@ -450,10 +450,10 @@ void EventDuplicate::undo() {
for (Event *event : selectedEvents) {
map->removeEvent(event);
if (editor->scene->items().contains(event->pixmapItem)) {
editor->scene->removeItem(event->pixmapItem);
if (editor->scene->items().contains(event->getPixmapItem())) {
editor->scene->removeItem(event->getPixmapItem());
}
editor->selected_events->removeOne(event->pixmapItem);
editor->selected_events->removeOne(event->getPixmapItem());
}
editor->shouldReselectEvents();
@ -471,7 +471,7 @@ int EventDuplicate::id() const {
EventPaste::EventPaste(Editor *editor, Map *map,
QList<Event *> pastedEvents,
QUndoCommand *parent) : EventDuplicate(editor, map, pastedEvents) {
QUndoCommand *parent) : EventDuplicate(editor, map, pastedEvents, parent) {
if (pastedEvents.size() > 1) {
setText("Paste Events");
} else {

View file

@ -1,480 +0,0 @@
#include "event.h"
#include "map.h"
#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_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),
spriteHeight(16),
usingSprite(false)
{ }
Event::Event(const Event& toCopy) :
values(toCopy.values),
customValues(toCopy.customValues),
pixmap(toCopy.pixmap),
spriteWidth(toCopy.spriteWidth),
spriteHeight(toCopy.spriteHeight),
frame(toCopy.frame),
hFlip(toCopy.hFlip),
usingSprite(toCopy.usingSprite)
{ }
Event::Event(QJsonObject obj, QString type) : Event()
{
this->put("event_type", type);
this->readCustomValues(obj);
}
Event* Event::createNewEvent(QString event_type, QString map_name, Project *project)
{
Event *event = nullptr;
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) {
event = createNewHealLocationEvent(map_name);
} else if (event_type == EventType::Trigger) {
event = createNewTriggerEvent(project);
} else if (event_type == EventType::WeatherTrigger) {
event = createNewWeatherTriggerEvent(project);
} else if (event_type == EventType::Sign) {
event = createNewSignEvent(project);
} else if (event_type == EventType::HiddenItem) {
event = createNewHiddenItemEvent(project);
} else if (event_type == EventType::SecretBase) {
event = createNewSecretBaseEvent(project);
} else {
// should never be reached but just in case
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;
}
Event* Event::createNewObjectEvent(Project *project)
{
Event *event = new Event;
event->put("sprite", project->gfxDefines.keys().first());
event->put("movement_type", project->movementTypes.first());
event->put("radius_x", 0);
event->put("radius_y", 0);
event->put("script_label", "NULL");
event->put("event_flag", "0");
event->put("replacement", "0");
event->put("trainer_type", project->trainerTypes.value(0, "0"));
event->put("sight_radius_tree_id", 0);
event->put("elevation", 3);
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("destination_warp", 0);
event->put("destination_map_name", map_name);
event->put("elevation", 0);
return event;
}
Event* Event::createNewHealLocationEvent(QString map_name)
{
Event *event = new Event;
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);
if (projectConfig.getHealLocationRespawnDataEnabled()) {
event->put("respawn_map", map_name);
event->put("respawn_npc", 1);
}
return event;
}
Event* Event::createNewTriggerEvent(Project *project)
{
Event *event = new Event;
event->put("script_label", "NULL");
event->put("script_var", project->varNames.first());
event->put("script_var_value", "0");
event->put("elevation", 0);
return event;
}
Event* Event::createNewWeatherTriggerEvent(Project *project)
{
Event *event = new Event;
event->put("weather", project->coordEventWeatherNames.first());
event->put("elevation", 0);
return event;
}
Event* Event::createNewSignEvent(Project *project)
{
Event *event = new Event;
event->put("player_facing_direction", project->bgEventFacingDirections.first());
event->put("script_label", "NULL");
event->put("elevation", 0);
return event;
}
Event* Event::createNewHiddenItemEvent(Project *project)
{
Event *event = new Event;
event->put("item", project->itemNames.first());
event->put("flag", project->flagNames.first());
event->put("elevation", 3);
if (projectConfig.getHiddenItemQuantityEnabled()) {
event->put("quantity", 1);
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
event->put("underfoot", false);
}
return event;
}
Event* Event::createNewSecretBaseEvent(Project *project)
{
Event *event = new Event;
event->put("secret_base_id", project->secretBaseIds.first());
event->put("elevation", 0);
return event;
}
int Event::getPixelX()
{
return (this->x() * 16) - qMax(0, (this->spriteWidth - 16) / 2);
}
int Event::getPixelY()
{
return (this->y() * 16) - qMax(0, this->spriteHeight - 16);
}
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",
};
const QSet<QString> expectedCloneObjectFields = {
"type",
"graphics_id",
"target_local_id",
"target_map",
};
const QSet<QString> expectedWarpFields = {
"elevation",
"dest_map",
"dest_warp_id",
};
const QSet<QString> expectedTriggerFields = {
"type",
"elevation",
"var",
"var_value",
"script",
};
const QSet<QString> expectedWeatherTriggerFields = {
"type",
"elevation",
"weather",
};
const QSet<QString> expectedSignFields = {
"type",
"elevation",
"player_facing_dir",
"script",
};
const QSet<QString> expectedHiddenItemFields = {
"type",
"elevation",
"item",
"flag",
};
const QSet<QString> expectedSecretBaseFields = {
"type",
"elevation",
"secret_base_id",
};
QSet<QString> Event::getExpectedFields()
{
QString type = this->get("event_type");
QSet<QString> expectedFields = QSet<QString>();
if (type == EventType::Object) {
expectedFields = expectedObjectFields;
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) {
expectedFields = expectedTriggerFields;
} else if (type == EventType::WeatherTrigger) {
expectedFields = expectedWeatherTriggerFields;
} else if (type == EventType::Sign) {
expectedFields = expectedSignFields;
} else if (type == EventType::HiddenItem) {
expectedFields = expectedHiddenItemFields;
if (projectConfig.getHiddenItemQuantityEnabled()) {
expectedFields.insert("quantity");
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
expectedFields.insert("underfoot");
}
} else if (type == EventType::SecretBase) {
expectedFields = expectedSecretBaseFields;
}
expectedFields << "x" << "y";
return expectedFields;
};
void Event::readCustomValues(QJsonObject values)
{
this->customValues.clear();
QSet<QString> expectedFields = this->getExpectedFields();
for (QString key : values.keys()) {
if (!expectedFields.contains(key)) {
this->customValues[key] = values[key].toString();
}
}
}
void Event::addCustomValuesTo(OrderedJson::object *obj)
{
for (QString key : this->customValues.keys()) {
if (!obj->contains(key)) {
(*obj)[key] = this->customValues[key];
}
}
}
OrderedJson::object Event::buildObjectEventJSON()
{
OrderedJson::object objectObj;
if (projectConfig.getEventCloneObjectEnabled()) {
objectObj["type"] = "object";
}
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 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)
{
OrderedJson::object warpObj;
warpObj["x"] = this->getU16("x");
warpObj["y"] = this->getU16("y");
warpObj["elevation"] = this->getInt("elevation");
warpObj["dest_map"] = mapNamesToMapConstants.value(this->get("destination_map_name"));
warpObj["dest_warp_id"] = this->getInt("destination_warp");
this->addCustomValuesTo(&warpObj);
return warpObj;
}
OrderedJson::object Event::buildTriggerEventJSON()
{
OrderedJson::object triggerObj;
triggerObj["type"] = "trigger";
triggerObj["x"] = this->getU16("x");
triggerObj["y"] = this->getU16("y");
triggerObj["elevation"] = this->getInt("elevation");
triggerObj["var"] = this->get("script_var");
triggerObj["var_value"] = this->get("script_var_value");
triggerObj["script"] = this->get("script_label");
this->addCustomValuesTo(&triggerObj);
return triggerObj;
}
OrderedJson::object Event::buildWeatherTriggerEventJSON()
{
OrderedJson::object weatherObj;
weatherObj["type"] = "weather";
weatherObj["x"] = this->getU16("x");
weatherObj["y"] = this->getU16("y");
weatherObj["elevation"] = this->getInt("elevation");
weatherObj["weather"] = this->get("weather");
this->addCustomValuesTo(&weatherObj);
return weatherObj;
}
OrderedJson::object Event::buildSignEventJSON()
{
OrderedJson::object signObj;
signObj["type"] = "sign";
signObj["x"] = this->getU16("x");
signObj["y"] = this->getU16("y");
signObj["elevation"] = this->getInt("elevation");
signObj["player_facing_dir"] = this->get("player_facing_direction");
signObj["script"] = this->get("script_label");
this->addCustomValuesTo(&signObj);
return signObj;
}
OrderedJson::object Event::buildHiddenItemEventJSON()
{
OrderedJson::object hiddenItemObj;
hiddenItemObj["type"] = "hidden_item";
hiddenItemObj["x"] = this->getU16("x");
hiddenItemObj["y"] = this->getU16("y");
hiddenItemObj["elevation"] = this->getInt("elevation");
hiddenItemObj["item"] = this->get("item");
hiddenItemObj["flag"] = this->get("flag");
if (projectConfig.getHiddenItemQuantityEnabled()) {
hiddenItemObj["quantity"] = this->getInt("quantity");
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
hiddenItemObj["underfoot"] = this->getInt("underfoot") > 0 || this->get("underfoot") == "TRUE";
}
this->addCustomValuesTo(&hiddenItemObj);
return hiddenItemObj;
}
OrderedJson::object Event::buildSecretBaseEventJSON()
{
OrderedJson::object secretBaseObj;
secretBaseObj["type"] = "secret_base";
secretBaseObj["x"] = this->getU16("x");
secretBaseObj["y"] = this->getU16("y");
secretBaseObj["elevation"] = this->getInt("elevation");
secretBaseObj["secret_base_id"] = this->get("secret_base_id");
this->addCustomValuesTo(&secretBaseObj);
return secretBaseObj;
}
void Event::setPixmapFromSpritesheet(QImage spritesheet, int spriteWidth, int spriteHeight, bool inanimate)
{
int frame = inanimate ? 0 : this->frame;
QImage img = spritesheet.copy(frame * spriteWidth % spritesheet.width(), 0, spriteWidth, spriteHeight);
if (this->hFlip && !inanimate) {
img = img.transformed(QTransform().scale(-1, 1));
}
// Set first palette color fully transparent.
img.setColor(0, qRgba(0, 0, 0, 0));
pixmap = QPixmap::fromImage(img);
this->spriteWidth = spriteWidth;
this->spriteHeight = spriteHeight;
this->usingSprite = true;
}
void Event::setFrameFromMovement(QString facingDir) {
// defaults
this->frame = 0;
this->hFlip = false;
if (facingDir == "DIR_NORTH") {
this->frame = 1;
this->hFlip = false;
} else if (facingDir == "DIR_SOUTH") {
this->frame = 0;
this->hFlip = false;
} else if (facingDir == "DIR_WEST") {
this->frame = 2;
this->hFlip = false;
} else if (facingDir == "DIR_EAST") {
this->frame = 2;
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());
}

895
src/core/events.cpp Normal file
View file

@ -0,0 +1,895 @@
#include "events.h"
#include "eventframes.h"
#include "project.h"
#include "config.h"
Event::~Event() {
if (this->eventFrame)
this->eventFrame->deleteLater();
}
EventFrame *Event::getEventFrame() {
if (!this->eventFrame) createEventFrame();
return this->eventFrame;
}
void Event::destroyEventFrame() {
if (this->eventFrame) delete this->eventFrame;
this->eventFrame = nullptr;
}
void Event::setPixmapItem(DraggablePixmapItem *item) {
this->pixmapItem = item;
if (this->eventFrame) {
this->eventFrame->invalidateConnections();
}
}
int Event::getEventIndex() {
return this->map->events.value(this->getEventGroup()).indexOf(this);
}
void Event::setDefaultValues(Project *) {
this->setX(0);
this->setY(0);
this->setElevation(3);
}
void Event::readCustomValues(QJsonObject values) {
this->customValues.clear();
QSet<QString> expectedFields = this->getExpectedFields();
for (QString key : values.keys()) {
if (!expectedFields.contains(key)) {
this->customValues[key] = values[key].toString();
}
}
}
void Event::addCustomValuesTo(OrderedJson::object *obj) {
for (QString key : this->customValues.keys()) {
if (!obj->contains(key)) {
(*obj)[key] = this->customValues[key];
}
}
}
void Event::modify() {
this->map->modify();
}
QString Event::eventTypeToString(Event::Type type) {
switch (type) {
case Event::Type::Object:
return "event_object";
case Event::Type::CloneObject:
return "event_clone_object";
case Event::Type::Warp:
return "event_warp";
case Event::Type::Trigger:
return "event_trigger";
case Event::Type::WeatherTrigger:
return "event_weather_trigger";
case Event::Type::Sign:
return "event_sign";
case Event::Type::HiddenItem:
return "event_hidden_item";
case Event::Type::SecretBase:
return "event_secret_base";
case Event::Type::HealLocation:
return "event_healspot";
default:
return "";
}
}
Event::Type Event::eventTypeFromString(QString type) {
if (type == "event_object") {
return Event::Type::Object;
} else if (type == "event_clone_object") {
return Event::Type::CloneObject;
} else if (type == "event_warp") {
return Event::Type::Warp;
} else if (type == "event_trigger") {
return Event::Type::Trigger;
} else if (type == "event_weather_trigger") {
return Event::Type::WeatherTrigger;
} else if (type == "event_sign") {
return Event::Type::Sign;
} else if (type == "event_hidden_item") {
return Event::Type::HiddenItem;
} else if (type == "event_secret_base") {
return Event::Type::SecretBase;
} else if (type == "event_healspot") {
return Event::Type::HealLocation;
} else {
return Event::Type::None;
}
}
Event *ObjectEvent::duplicate() {
ObjectEvent *copy = new ObjectEvent();
copy->setX(this->getX());
copy->setY(this->getY());
copy->setElevation(this->getElevation());
copy->setGfx(this->getGfx());
copy->setMovement(this->getMovement());
copy->setRadiusX(this->getRadiusX());
copy->setRadiusY(this->getRadiusY());
copy->setTrainerType(this->getTrainerType());
copy->setSightRadiusBerryTreeID(this->getSightRadiusBerryTreeID());
copy->setScript(this->getScript());
copy->setFlag(this->getFlag());
copy->setCustomValues(this->getCustomValues());
return copy;
}
EventFrame *ObjectEvent::createEventFrame() {
if (!this->eventFrame) {
this->eventFrame = new ObjectFrame(this);
this->eventFrame->setup();
QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; });
}
return this->eventFrame;
}
OrderedJson::object ObjectEvent::buildEventJson(Project *) {
OrderedJson::object objectJson;
if (projectConfig.getEventCloneObjectEnabled()) {
objectJson["type"] = "object";
}
objectJson["graphics_id"] = this->getGfx();
objectJson["x"] = this->getX();
objectJson["y"] = this->getY();
objectJson["elevation"] = this->getElevation();
objectJson["movement_type"] = this->getMovement();
objectJson["movement_range_x"] = this->getRadiusX();
objectJson["movement_range_y"] = this->getRadiusY();
objectJson["trainer_type"] = this->getTrainerType();
objectJson["trainer_sight_or_berry_tree_id"] = this->getSightRadiusBerryTreeID();
objectJson["script"] = this->getScript();
objectJson["flag"] = this->getFlag();
this->addCustomValuesTo(&objectJson);
return objectJson;
}
bool ObjectEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt());
this->setY(json["y"].toInt());
this->setElevation(json["elevation"].toInt());
this->setGfx(json["graphics_id"].toString());
this->setMovement(json["movement_type"].toString());
this->setRadiusX(json["movement_range_x"].toInt());
this->setRadiusY(json["movement_range_y"].toInt());
this->setTrainerType(json["trainer_type"].toString());
this->setSightRadiusBerryTreeID(json["trainer_sight_or_berry_tree_id"].toString());
this->setScript(json["script"].toString());
this->setFlag(json["flag"].toString());
this->readCustomValues(json);
return true;
}
void ObjectEvent::setDefaultValues(Project *project) {
this->setGfx(project->gfxDefines.keys().first());
this->setMovement(project->movementTypes.first());
this->setScript("NULL");
this->setTrainerType(project->trainerTypes.value(0, "0"));
this->setRadiusX(0);
this->setRadiusY(0);
this->setFrameFromMovement(project->facingDirections.value(this->getMovement()));
}
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",
};
QSet<QString> ObjectEvent::getExpectedFields() {
QSet<QString> expectedFields = QSet<QString>();
expectedFields = expectedObjectFields;
if (projectConfig.getEventCloneObjectEnabled()) {
expectedFields.insert("type");
}
expectedFields << "x" << "y";
return expectedFields;
}
void ObjectEvent::loadPixmap(Project *project) {
EventGraphics *eventGfx = project->eventGraphicsMap.value(this->gfx, nullptr);
if (!eventGfx) {
// Invalid gfx constant.
// If this is a number, try to use that instead.
bool ok;
int altGfx = this->gfx.toInt(&ok);
if (ok && (altGfx < project->gfxDefines.count())) {
eventGfx = project->eventGraphicsMap.value(project->gfxDefines.key(altGfx, "NULL"), nullptr);
}
}
if (!eventGfx || eventGfx->spritesheet.isNull()) {
// No sprite associated with this gfx constant.
// Use default sprite instead.
this->pixmap = project->entitiesPixmap.copy(0, 0, 16, 16);
} else {
this->setFrameFromMovement(project->facingDirections.value(this->movement));
this->setPixmapFromSpritesheet(eventGfx->spritesheet, eventGfx->spriteWidth, eventGfx->spriteHeight, eventGfx->inanimate);
}
}
void ObjectEvent::setPixmapFromSpritesheet(QImage spritesheet, int spriteWidth, int spriteHeight, bool inanimate)
{
int frame = inanimate ? 0 : this->frame;
QImage img = spritesheet.copy(frame * spriteWidth % spritesheet.width(), 0, spriteWidth, spriteHeight);
if (this->hFlip && !inanimate) {
img = img.transformed(QTransform().scale(-1, 1));
}
// Set first palette color fully transparent.
img.setColor(0, qRgba(0, 0, 0, 0));
pixmap = QPixmap::fromImage(img);
this->spriteWidth = spriteWidth;
this->spriteHeight = spriteHeight;
this->usingSprite = true;
}
void ObjectEvent::setFrameFromMovement(QString facingDir) {
// defaults
// TODO: read this from a file somewhere?
this->frame = 0;
this->hFlip = false;
if (facingDir == "DIR_NORTH") {
this->frame = 1;
this->hFlip = false;
} else if (facingDir == "DIR_SOUTH") {
this->frame = 0;
this->hFlip = false;
} else if (facingDir == "DIR_WEST") {
this->frame = 2;
this->hFlip = false;
} else if (facingDir == "DIR_EAST") {
this->frame = 2;
this->hFlip = true;
}
}
Event *CloneObjectEvent::duplicate() {
CloneObjectEvent *copy = new CloneObjectEvent();
copy->setX(this->getX());
copy->setY(this->getY());
copy->setElevation(this->getElevation());
copy->setGfx(this->getGfx());
copy->setTargetID(this->getTargetID());
copy->setTargetMap(this->getTargetMap());
copy->setCustomValues(this->getCustomValues());
return copy;
}
EventFrame *CloneObjectEvent::createEventFrame() {
if (!this->eventFrame) {
this->eventFrame = new CloneObjectFrame(this);
this->eventFrame->setup();
QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; });
}
return this->eventFrame;
}
OrderedJson::object CloneObjectEvent::buildEventJson(Project *project) {
OrderedJson::object cloneJson;
cloneJson["type"] = "clone";
cloneJson["graphics_id"] = this->getGfx();
cloneJson["x"] = this->getX();
cloneJson["y"] = this->getY();
cloneJson["target_local_id"] = this->getTargetID();
cloneJson["target_map"] = project->mapNamesToMapConstants.value(this->getTargetMap());
this->addCustomValuesTo(&cloneJson);
return cloneJson;
}
bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) {
this->setX(json["x"].toInt());
this->setY(json["y"].toInt());
this->setGfx(json["graphics_id"].toString());
this->setTargetID(json["target_local_id"].toInt());
// Ensure the target map constant is valid before adding it to the events.
QString mapConstant = json["target_map"].toString();
if (project->mapConstantsToMapNames.contains(mapConstant)) {
this->setTargetMap(project->mapConstantsToMapNames.value(mapConstant));
} else if (mapConstant == NONE_MAP_CONSTANT) {
this->setTargetMap(NONE_MAP_NAME);
} else {
logError(QString("Destination map constant '%1' is invalid").arg(mapConstant));
return false;
}
this->readCustomValues(json);
return true;
}
void CloneObjectEvent::setDefaultValues(Project *project) {
this->setGfx(project->gfxDefines.keys().first());
this->setTargetID(1);
if (this->getMap()) this->setTargetMap(this->getMap()->name);
}
const QSet<QString> expectedCloneObjectFields = {
"type",
"graphics_id",
"target_local_id",
"target_map",
};
QSet<QString> CloneObjectEvent::getExpectedFields() {
QSet<QString> expectedFields = QSet<QString>();
expectedFields = expectedCloneObjectFields;
expectedFields << "x" << "y";
return expectedFields;
}
void CloneObjectEvent::loadPixmap(Project *project) {
// Try to get the targeted object to clone
int eventIndex = this->targetID - 1;
Map *clonedMap = project->getMap(this->targetMap);
Event *clonedEvent = clonedMap ? clonedMap->events[Event::Group::Object].value(eventIndex, nullptr) : nullptr;
if (clonedEvent && clonedEvent->getEventType() == Event::Type::Object) {
// Get graphics data from cloned object
ObjectEvent *clonedObject = dynamic_cast<ObjectEvent *>(clonedEvent);
this->gfx = clonedObject->getGfx();
this->movement = clonedObject->getMovement();
} else {
// Invalid object specified, use default graphics data (as would be shown in-game)
this->gfx = project->gfxDefines.key(0);
this->movement = project->movementTypes.first();
}
EventGraphics *eventGfx = project->eventGraphicsMap.value(gfx, nullptr);
if (!eventGfx || eventGfx->spritesheet.isNull()) {
// No sprite associated with this gfx constant.
// Use default sprite instead.
this->pixmap = project->entitiesPixmap.copy(0, 0, 16, 16);
} else {
this->setFrameFromMovement(project->facingDirections.value(this->movement));
this->setPixmapFromSpritesheet(eventGfx->spritesheet, eventGfx->spriteWidth, eventGfx->spriteHeight, eventGfx->inanimate);
}
}
Event *WarpEvent::duplicate() {
WarpEvent *copy = new WarpEvent();
copy->setX(this->getX());
copy->setY(this->getY());
copy->setElevation(this->getElevation());
copy->setDestinationMap(this->getDestinationMap());
copy->setDestinationWarpID(this->getDestinationWarpID());
copy->setCustomValues(this->getCustomValues());
return copy;
}
EventFrame *WarpEvent::createEventFrame() {
if (!this->eventFrame) {
this->eventFrame = new WarpFrame(this);
this->eventFrame->setup();
QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; });
}
return this->eventFrame;
}
OrderedJson::object WarpEvent::buildEventJson(Project *project) {
OrderedJson::object warpJson;
warpJson["x"] = this->getX();
warpJson["y"] = this->getY();
warpJson["elevation"] = this->getElevation();
warpJson["dest_map"] = project->mapNamesToMapConstants.value(this->getDestinationMap());
warpJson["dest_warp_id"] = this->getDestinationWarpID();
this->addCustomValuesTo(&warpJson);
return warpJson;
}
bool WarpEvent::loadFromJson(QJsonObject json, Project *project) {
this->setX(json["x"].toInt());
this->setY(json["y"].toInt());
this->setElevation(json["elevation"].toInt());
this->setDestinationWarpID(json["dest_warp_id"].toInt());
// Ensure the warp destination map constant is valid before adding it to the warps.
QString mapConstant = json["dest_map"].toString();
if (project->mapConstantsToMapNames.contains(mapConstant)) {
this->setDestinationMap(project->mapConstantsToMapNames.value(mapConstant));
} else if (mapConstant == NONE_MAP_CONSTANT) {
this->setDestinationMap(NONE_MAP_NAME);
} else {
logError(QString("Destination map constant '%1' is invalid for warp").arg(mapConstant));
return false;
}
this->readCustomValues(json);
return true;
}
void WarpEvent::setDefaultValues(Project *) {
if (this->getMap()) this->setDestinationMap(this->getMap()->name);
this->setDestinationWarpID(0);
this->setElevation(0);
}
const QSet<QString> expectedWarpFields = {
"elevation",
"dest_map",
"dest_warp_id",
};
QSet<QString> WarpEvent::getExpectedFields() {
QSet<QString> expectedFields = QSet<QString>();
expectedFields = expectedWarpFields;
expectedFields << "x" << "y";
return expectedFields;
}
void WarpEvent::loadPixmap(Project *project) {
this->pixmap = project->entitiesPixmap.copy(16, 0, 16, 16);
}
void CoordEvent::loadPixmap(Project *project) {
this->pixmap = project->entitiesPixmap.copy(32, 0, 16, 16);
}
Event *TriggerEvent::duplicate() {
TriggerEvent *copy = new TriggerEvent();
copy->setX(this->getX());
copy->setY(this->getY());
copy->setElevation(this->getElevation());
copy->setScriptVar(this->getScriptVar());
copy->setScriptVarValue(this->getScriptVarValue());
copy->setScriptLabel(this->getScriptLabel());
copy->setCustomValues(this->getCustomValues());
return copy;
}
EventFrame *TriggerEvent::createEventFrame() {
if (!this->eventFrame) {
this->eventFrame = new TriggerFrame(this);
this->eventFrame->setup();
QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; });
}
return this->eventFrame;
}
OrderedJson::object TriggerEvent::buildEventJson(Project *) {
OrderedJson::object triggerJson;
triggerJson["type"] = "trigger";
triggerJson["x"] = this->getX();
triggerJson["y"] = this->getY();
triggerJson["elevation"] = this->getElevation();
triggerJson["var"] = this->getScriptVar();
triggerJson["var_value"] = this->getScriptVarValue();
triggerJson["script"] = this->getScriptLabel();
this->addCustomValuesTo(&triggerJson);
return triggerJson;
}
bool TriggerEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt());
this->setY(json["y"].toInt());
this->setElevation(json["elevation"].toInt());
this->setScriptVar(json["var"].toString());
this->setScriptVarValue(json["var_value"].toString());
this->setScriptLabel(json["script"].toString());
this->readCustomValues(json);
return true;
}
void TriggerEvent::setDefaultValues(Project *project) {
this->setScriptLabel("NULL");
this->setScriptVar(project->varNames.first());
this->setScriptVarValue("0");
this->setElevation(0);
}
const QSet<QString> expectedTriggerFields = {
"type",
"elevation",
"var",
"var_value",
"script",
};
QSet<QString> TriggerEvent::getExpectedFields() {
QSet<QString> expectedFields = QSet<QString>();
expectedFields = expectedTriggerFields;
expectedFields << "x" << "y";
return expectedFields;
}
Event *WeatherTriggerEvent::duplicate() {
WeatherTriggerEvent *copy = new WeatherTriggerEvent();
copy->setX(this->getX());
copy->setY(this->getY());
copy->setElevation(this->getElevation());
copy->setWeather(this->getWeather());
copy->setCustomValues(this->getCustomValues());
return copy;
}
EventFrame *WeatherTriggerEvent::createEventFrame() {
if (!this->eventFrame) {
this->eventFrame = new WeatherTriggerFrame(this);
this->eventFrame->setup();
QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; });
}
return this->eventFrame;
}
OrderedJson::object WeatherTriggerEvent::buildEventJson(Project *) {
OrderedJson::object weatherJson;
weatherJson["type"] = "weather";
weatherJson["x"] = this->getX();
weatherJson["y"] = this->getY();
weatherJson["elevation"] = this->getElevation();
weatherJson["weather"] = this->getWeather();
this->addCustomValuesTo(&weatherJson);
return weatherJson;
}
bool WeatherTriggerEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt());
this->setY(json["y"].toInt());
this->setElevation(json["elevation"].toInt());
this->setWeather(json["weather"].toString());
this->readCustomValues(json);
return true;
}
void WeatherTriggerEvent::setDefaultValues(Project *project) {
this->setWeather(project->coordEventWeatherNames.first());
this->setElevation(0);
}
const QSet<QString> expectedWeatherTriggerFields = {
"type",
"elevation",
"weather",
};
QSet<QString> WeatherTriggerEvent::getExpectedFields() {
QSet<QString> expectedFields = QSet<QString>();
expectedFields = expectedWeatherTriggerFields;
expectedFields << "x" << "y";
return expectedFields;
}
void BGEvent::loadPixmap(Project *project) {
this->pixmap = project->entitiesPixmap.copy(48, 0, 16, 16);
}
Event *SignEvent::duplicate() {
SignEvent *copy = new SignEvent();
copy->setX(this->getX());
copy->setY(this->getY());
copy->setElevation(this->getElevation());
copy->setFacingDirection(this->getFacingDirection());
copy->setScriptLabel(this->getScriptLabel());
copy->setCustomValues(this->getCustomValues());
return copy;
}
EventFrame *SignEvent::createEventFrame() {
if (!this->eventFrame) {
this->eventFrame = new SignFrame(this);
this->eventFrame->setup();
QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; });
}
return this->eventFrame;
}
OrderedJson::object SignEvent::buildEventJson(Project *) {
OrderedJson::object signJson;
signJson["type"] = "sign";
signJson["x"] = this->getX();
signJson["y"] = this->getY();
signJson["elevation"] = this->getElevation();
signJson["player_facing_dir"] = this->getFacingDirection();
signJson["script"] = this->getScriptLabel();
this->addCustomValuesTo(&signJson);
return signJson;
}
bool SignEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt());
this->setY(json["y"].toInt());
this->setElevation(json["elevation"].toInt());
this->setFacingDirection(json["player_facing_dir"].toString());
this->setScriptLabel(json["script"].toString());
this->readCustomValues(json);
return true;
}
void SignEvent::setDefaultValues(Project *project) {
this->setFacingDirection(project->bgEventFacingDirections.first());
this->setScriptLabel("NULL");
this->setElevation(0);
}
const QSet<QString> expectedSignFields = {
"type",
"elevation",
"player_facing_dir",
"script",
};
QSet<QString> SignEvent::getExpectedFields() {
QSet<QString> expectedFields = QSet<QString>();
expectedFields = expectedSignFields;
expectedFields << "x" << "y";
return expectedFields;
}
Event *HiddenItemEvent::duplicate() {
HiddenItemEvent *copy = new HiddenItemEvent();
copy->setX(this->getX());
copy->setY(this->getY());
copy->setElevation(this->getElevation());
copy->setItem(this->getItem());
copy->setFlag(this->getFlag());
copy->setQuantity(this->getQuantity());
copy->setQuantity(this->getQuantity());
copy->setCustomValues(this->getCustomValues());
return copy;
}
EventFrame *HiddenItemEvent::createEventFrame() {
if (!this->eventFrame) {
this->eventFrame = new HiddenItemFrame(this);
this->eventFrame->setup();
QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; });
}
return this->eventFrame;
}
OrderedJson::object HiddenItemEvent::buildEventJson(Project *) {
OrderedJson::object hiddenItemJson;
hiddenItemJson["type"] = "hidden_item";
hiddenItemJson["x"] = this->getX();
hiddenItemJson["y"] = this->getY();
hiddenItemJson["elevation"] = this->getElevation();
hiddenItemJson["item"] = this->getItem();
hiddenItemJson["flag"] = this->getFlag();
if (projectConfig.getHiddenItemQuantityEnabled()) {
hiddenItemJson["quantity"] = this->getQuantity();
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
hiddenItemJson["underfoot"] = this->getUnderfoot();
}
this->addCustomValuesTo(&hiddenItemJson);
return hiddenItemJson;
}
bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt());
this->setY(json["y"].toInt());
this->setElevation(json["elevation"].toInt());
this->setItem(json["item"].toString());
this->setFlag(json["flag"].toString());
if (projectConfig.getHiddenItemQuantityEnabled()) {
this->setQuantity(json["quantity"].toInt());
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
this->setUnderfoot(json["underfoot"].toBool());
}
this->readCustomValues(json);
return true;
}
void HiddenItemEvent::setDefaultValues(Project *project) {
this->setItem(project->itemNames.first());
this->setFlag(project->flagNames.first());
if (projectConfig.getHiddenItemQuantityEnabled()) {
this->setQuantity(1);
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
this->setUnderfoot(false);
}
}
const QSet<QString> expectedHiddenItemFields = {
"type",
"elevation",
"item",
"flag",
};
QSet<QString> HiddenItemEvent::getExpectedFields() {
QSet<QString> expectedFields = QSet<QString>();
expectedFields = expectedHiddenItemFields;
if (projectConfig.getHiddenItemQuantityEnabled()) {
expectedFields << "quantity";
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
expectedFields << "underfoot";
}
expectedFields << "x" << "y";
return expectedFields;
}
Event *SecretBaseEvent::duplicate() {
SecretBaseEvent *copy = new SecretBaseEvent();
copy->setX(this->getX());
copy->setY(this->getY());
copy->setElevation(this->getElevation());
copy->setBaseID(this->getBaseID());
copy->setCustomValues(this->getCustomValues());
return copy;
}
EventFrame *SecretBaseEvent::createEventFrame() {
if (!this->eventFrame) {
this->eventFrame = new SecretBaseFrame(this);
this->eventFrame->setup();
QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; });
}
return this->eventFrame;
}
OrderedJson::object SecretBaseEvent::buildEventJson(Project *) {
OrderedJson::object secretBaseJson;
secretBaseJson["type"] = "secret_base";
secretBaseJson["x"] = this->getX();
secretBaseJson["y"] = this->getY();
secretBaseJson["elevation"] = this->getElevation();
secretBaseJson["secret_base_id"] = this->getBaseID();
this->addCustomValuesTo(&secretBaseJson);
return secretBaseJson;
}
bool SecretBaseEvent::loadFromJson(QJsonObject json, Project *) {
this->setX(json["x"].toInt());
this->setY(json["y"].toInt());
this->setElevation(json["elevation"].toInt());
this->setBaseID(json["secret_base_id"].toString());
this->readCustomValues(json);
return true;
}
void SecretBaseEvent::setDefaultValues(Project *project) {
this->setBaseID(project->secretBaseIds.first());
this->setElevation(0);
}
const QSet<QString> expectedSecretBaseFields = {
"type",
"elevation",
"secret_base_id",
};
QSet<QString> SecretBaseEvent::getExpectedFields() {
QSet<QString> expectedFields = QSet<QString>();
expectedFields = expectedSecretBaseFields;
expectedFields << "x" << "y";
return expectedFields;
}
EventFrame *HealLocationEvent::createEventFrame() {
if (!this->eventFrame) {
this->eventFrame = new HealLocationFrame(this);
this->eventFrame->setup();
QObject::connect(this->eventFrame, &QObject::destroyed, [this](){ this->eventFrame = nullptr; });
}
return this->eventFrame;
}
OrderedJson::object HealLocationEvent::buildEventJson(Project *) {
return OrderedJson::object();
}
void HealLocationEvent::setDefaultValues(Project *) {
if (this->getMap()) {
this->setLocationName(Map::mapConstantFromName(this->getMap()->name).remove(0,4));
this->setIdName(this->getMap()->name.replace(QRegularExpression("([a-z])([A-Z])"), "\\1_\\2").toUpper());
}
this->setElevation(3);
if (projectConfig.getHealLocationRespawnDataEnabled()) {
if (this->getMap()) this->setRespawnMap(this->getMap()->name);
this->setRespawnNPC(1);
}
}
void HealLocationEvent::loadPixmap(Project *project) {
this->pixmap = project->entitiesPixmap.copy(64, 0, 16, 16);
}

View file

@ -1,9 +1,11 @@
#include "heallocation.h"
#include "config.h"
#include "events.h"
#include "map.h"
HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t y, QString respawnMap, uint16_t respawnNPC)
{
HealLocation::HealLocation(QString id, QString map,
int i, uint16_t x, uint16_t y,
QString respawnMap, uint16_t respawnNPC) {
this->idName = id;
this->mapName = map;
this->index = i;
@ -13,28 +15,23 @@ HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t
this->respawnNPC = respawnNPC;
}
HealLocation HealLocation::fromEvent(Event *event)
{
HealLocation hl;
hl.idName = event->get("id_name");
hl.mapName = event->get("loc_name");
try {
hl.index = event->get("index").toInt();
}
catch(...) {
hl.index = 0;
}
hl.x = event->getU16("x");
hl.y = event->getU16("y");
HealLocation HealLocation::fromEvent(Event *fromEvent) {
HealLocationEvent *event = dynamic_cast<HealLocationEvent *>(fromEvent);
HealLocation healLocation;
healLocation.idName = event->getIdName();
healLocation.mapName = event->getLocationName();
healLocation.index = event->getIndex();
healLocation.x = event->getX();
healLocation.y = event->getY();
if (projectConfig.getHealLocationRespawnDataEnabled()) {
hl.respawnNPC = event->getU16("respawn_npc");
hl.respawnMap = Map::mapConstantFromName(event->get("respawn_map")).remove(0,4);
healLocation.respawnNPC = event->getRespawnNPC();
healLocation.respawnMap = Map::mapConstantFromName(event->getRespawnMap()).remove(0,4);
}
return hl;
return healLocation;
}
QDebug operator<<(QDebug debug, const HealLocation &hl)
{
debug << "HealLocation_" + hl.mapName << "(" << hl.x << ',' << hl.y << ")";
QDebug operator<<(QDebug debug, const HealLocation &healLocation) {
debug << "HealLocation_" + healLocation.mapName << "(" << healLocation.x << ',' << healLocation.y << ")";
return debug;
}

View file

@ -340,6 +340,10 @@ void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata,
emit mapChanged(this);
}
void Map::openScript(QString label) {
emit openScriptRequested(label);
}
bool Map::getBlock(int x, int y, Block *out) {
if (isWithinBounds(x, y)) {
int i = y * getWidth() + x;
@ -474,37 +478,51 @@ QList<Event *> Map::getAllEvents() const {
return all_events;
}
QStringList Map::eventScriptLabels(const QString &event_group_type) const {
QStringList Map::eventScriptLabels(Event::Group group) const {
QStringList scriptLabels;
if (event_group_type.isEmpty()) {
for (const auto *event : getAllEvents())
scriptLabels << event->get("script_label");
if (group == Event::Group::None) {
ScriptTracker scriptTracker;
for (Event *event : this->getAllEvents()) {
event->accept(&scriptTracker);
}
scriptLabels = scriptTracker.getScripts();
} else {
for (const auto *event : events.value(event_group_type))
scriptLabels << event->get("script_label");
ScriptTracker scriptTracker;
for (Event *event : events.value(group)) {
event->accept(&scriptTracker);
}
scriptLabels = scriptTracker.getScripts();
}
scriptLabels.removeAll("");
scriptLabels.removeDuplicates();
if (scriptLabels.contains("0x0"))
scriptLabels.move(scriptLabels.indexOf("0x0"), scriptLabels.count() - 1);
if (scriptLabels.contains("NULL"))
scriptLabels.move(scriptLabels.indexOf("NULL"), scriptLabels.count() - 1);
scriptLabels.prepend("0x0");
scriptLabels.prepend("NULL");
return scriptLabels;
}
void Map::removeEvent(Event *event) {
for (QString key : events.keys()) {
for (Event::Group key : events.keys()) {
events[key].removeAll(event);
}
}
void Map::addEvent(Event *event) {
events[event->get("event_group_type")].append(event);
event->setMap(this);
events[event->getEventGroup()].append(event);
if (!ownedEvents.contains(event)) ownedEvents.append(event);
}
void Map::modify() {
emit modified();
}
void Map::clean() {
this->hasUnsavedDataChanges = false;
}
bool Map::hasUnsavedChanges() {
return !editHistory.isClean() || hasUnsavedDataChanges || !isPersistedToFile;
}

View file

@ -15,6 +15,8 @@ const QRegularExpression ParseUtil::re_poryScriptLabel("\\b(script)(\\((global|l
const QRegularExpression ParseUtil::re_globalPoryScriptLabel("\\b(script)(\\((global)\\))?\\s*\\b(?<label>[\\w_][\\w\\d_]*)");
const QRegularExpression ParseUtil::re_poryRawSection("\\b(raw)\\s*`(?<raw_script>[^`]*)");
using OrderedJson = poryjson::Json;
void ParseUtil::set_root(const QString &dir) {
this->root = dir;
}

View file

@ -268,14 +268,14 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
this->layout_array_label = label;
QRegularExpression rowRe("{(?<row>[A-Z0-9_, ]+)}");
QRegularExpressionMatchIterator j = rowRe.globalMatch(text);
QRegularExpressionMatchIterator k = rowRe.globalMatch(text);
this->layout_layers.append("main");
QList<LayoutSquare> layout;
int y = 0;
while (j.hasNext()) {
QRegularExpressionMatch n = j.next();
while (k.hasNext()) {
QRegularExpressionMatch n = k.next();
QString row = n.captured("row");
QStringList rowSections = row.split(',');
int x = 0;
@ -357,7 +357,7 @@ poryjson::Json::object RegionMap::config() {
layoutObject["height"] = this->layout_height;
layoutObject["offset_left"] = this->offset_left;
layoutObject["offset_top"] = this->offset_top;
QMap<LayoutFormat, QString> layoutFormatMap = { {LayoutFormat::Binary, "binary"}, {LayoutFormat::CArray, "C array"} };
static QMap<LayoutFormat, QString> layoutFormatMap = { {LayoutFormat::Binary, "binary"}, {LayoutFormat::CArray, "C array"} };
layoutObject["format"] = layoutFormatMap[this->layout_format];
layoutObject["path"] = this->layout_path;
config["layout"] = layoutObject;
@ -405,11 +405,26 @@ void RegionMap::saveLayout() {
}
text += " = {\n";
if (this->layout_layers.size() == 1) {
if (this->layout_constants.count() == 1) {
for (LayoutSquare s : this->getLayout("main")) {
text += " " + s.map_section + ",\n";
}
text.chop(2);
text += "\n";
} else if (this->layout_constants.count() == 2) {
for (int row = 0; row < this->layout_height; row++) {
text += " {";
for (int col = 0; col < this->layout_width; col++) {
int i = col + row * this->layout_width;
text += this->layouts["main"][i].map_section + ", ";
}
text.chop(2);
text += "},-\n";
}
} else {
logError(QString("Failed to save region map layout for %1").arg(this->layout_array_label));
return;
}
} else {
// multi layered
for (auto layoutName : this->layout_layers) {

View file

@ -260,7 +260,8 @@ void ResizeTilemap::undo() {
///
ClearEntries::ClearEntries(RegionMap *map, tsl::ordered_map<QString, MapSectionEntry> entries, QUndoCommand *parent) {
ClearEntries::ClearEntries(RegionMap *map, tsl::ordered_map<QString, MapSectionEntry> entries, QUndoCommand *parent)
: QUndoCommand(parent) {
setText("Clear Entries");
this->map = map;

View file

@ -1,6 +1,5 @@
#include "editor.h"
#include "draggablepixmapitem.h"
#include "event.h"
#include "imageproviders.h"
#include "log.h"
#include "mapconnection.h"
@ -1093,6 +1092,12 @@ bool Editor::setMap(QString map_name) {
return false;
}
// disconnect previous map's signals so they are not firing
// multiple times if set again in the future
if (map) {
map->disconnect(this);
}
if (project) {
Map *loadedMap = project->loadMap(map_name);
if (!loadedMap) {
@ -1109,6 +1114,7 @@ bool Editor::setMap(QString map_name) {
}
map_ruler->setMapDimensions(QSize(map->getWidth(), map->getHeight()));
connect(map, &Map::mapDimensionsChanged, map_ruler, &MapRuler::setMapDimensions);
connect(map, &Map::openScriptRequested, this, &Editor::openScript);
updateSelectedEvents();
}
@ -1230,12 +1236,12 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item
// Left-clicking while in paint mode will add a new event of the
// type of the first currently selected events.
// Disallow adding heal locations, deleting them is not possible yet
QString eventType = EventType::Object;
Event::Type eventType = Event::Type::Object;
if (this->selected_events->size() > 0)
eventType = this->selected_events->first()->event->get("event_type");
eventType = this->selected_events->first()->event->getEventType();
if (eventType != EventType::HealLocation) {
DraggablePixmapItem * newEvent = addNewEvent(eventType);
if (eventType != Event::Type::HealLocation) {
DraggablePixmapItem *newEvent = addNewEvent(eventType);
if (newEvent) {
newEvent->move(pos.x(), pos.y());
emit objectsChanged();
@ -1250,7 +1256,6 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item
static unsigned actionId = 0;
if (event->type() == QEvent::GraphicsSceneMouseRelease) {
// TODO: commit / update history here
actionId++;
} else {
if (event->type() == QEvent::GraphicsSceneMousePress) {
@ -1516,7 +1521,6 @@ void Editor::displayMapEvents() {
DraggablePixmapItem *Editor::addMapEvent(Event *event) {
DraggablePixmapItem *object = new DraggablePixmapItem(event, this);
event->setPixmapItem(object);
this->redrawObject(object);
events_group->addToGroup(object);
return object;
@ -1999,15 +2003,16 @@ QList<DraggablePixmapItem *> Editor::getObjects() {
}
void Editor::redrawObject(DraggablePixmapItem *item) {
if (item && item->event && !item->event->pixmap.isNull()) {
qreal opacity = item->event->usingSprite ? 1.0 : 0.7;
if (item && item->event && !item->event->getPixmap().isNull()) {
qreal opacity = item->event->getUsingSprite() ? 1.0 : 0.7;
item->setOpacity(opacity);
item->setPixmap(item->event->pixmap.copy(item->event->frame * item->event->spriteWidth % item->event->pixmap.width(), 0, item->event->spriteWidth, item->event->spriteHeight));
project->setEventPixmap(item->event, true);
item->setPixmap(item->event->getPixmap());
item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
if (selected_events && selected_events->contains(item)) {
QImage image = item->pixmap().toImage();
QPainter painter(&image);
painter.setPen(QColor(250, 0, 255));
painter.setPen(QColor(255, 0, 255));
painter.drawRect(0, 0, image.width() - 1, image.height() - 1);
painter.end();
item->setPixmap(QPixmap::fromImage(image));
@ -2025,7 +2030,7 @@ void Editor::updateSelectedEvents() {
redrawObject(item);
}
emit selectedObjectsChanged();
emit objectsChanged();
}
void Editor::selectMapEvent(DraggablePixmapItem *object) {
@ -2048,6 +2053,29 @@ void Editor::selectMapEvent(DraggablePixmapItem *object, bool toggle) {
}
}
void Editor::selectedEventIndexChanged(int index, Event::Group eventGroup) {
int event_offs = Event::getIndexOffset(eventGroup);
index = index - event_offs;
Event *event = nullptr;
if (index < this->map->events.value(eventGroup).length()) {
event = this->map->events.value(eventGroup).at(index);
}
DraggablePixmapItem *selectedEvent = nullptr;
for (QGraphicsItem *child : this->events_group->childItems()) {
DraggablePixmapItem *item = static_cast<DraggablePixmapItem *>(child);
if (item->event == event) {
selectedEvent = item;
break;
}
}
if (selectedEvent) {
this->selectMapEvent(selectedEvent);
} else {
updateSelectedEvents();
}
}
void Editor::duplicateSelectedEvents() {
if (!selected_events || !selected_events->length() || !map || !current_view || map_item->paintingMode != MapPixmapItem::PaintMode::EventObjects)
return;
@ -2055,60 +2083,89 @@ void Editor::duplicateSelectedEvents() {
QList<Event *> selectedEvents;
for (int i = 0; i < selected_events->length(); i++) {
Event *original = selected_events->at(i)->event;
QString eventType = original->get("event_type");
Event::Type eventType = original->getEventType();
if (eventLimitReached(eventType)) {
logWarn(QString("Skipping duplication, the map limit for events of type '%1' has been reached.").arg(eventType));
logWarn(QString("Skipping duplication, the map limit for events of type '%1' has been reached.").arg(Event::eventTypeToString(eventType)));
continue;
}
if (eventType == EventType::HealLocation) continue;
Event *duplicate = new Event(*original);
duplicate->setX(duplicate->x() + 1);
duplicate->setY(duplicate->y() + 1);
if (eventType == Event::Type::HealLocation) {
logWarn("Skipping duplication, event is a heal location.");
continue;
}
Event *duplicate = original->duplicate();
if (!duplicate) {
logError("Encountered a problem duplicating an event.");
continue;
}
duplicate->setX(duplicate->getX() + 1);
duplicate->setY(duplicate->getY() + 1);
selectedEvents.append(duplicate);
}
map->editHistory.push(new EventDuplicate(this, map, selectedEvents));
}
DraggablePixmapItem* Editor::addNewEvent(QString event_type) {
if (project && map && !event_type.isEmpty() && !eventLimitReached(event_type)) {
Event *event = Event::createNewEvent(event_type, map->name, project);
event->put("map_name", map->name);
if (event_type == EventType::HealLocation) {
HealLocation hl = HealLocation::fromEvent(event);
project->healLocations.append(hl);
event->put("index", project->healLocations.length());
}
map->editHistory.push(new EventCreate(this, map, event));
DraggablePixmapItem *Editor::addNewEvent(Event::Type type) {
Event *event = nullptr;
return event->pixmapItem;
if (project && map && !eventLimitReached(type)) {
switch (type) {
case Event::Type::Object:
event = new ObjectEvent();
break;
case Event::Type::CloneObject:
event = new CloneObjectEvent();
break;
case Event::Type::Warp:
event = new WarpEvent();
break;
case Event::Type::Trigger:
event = new TriggerEvent();
break;
case Event::Type::WeatherTrigger:
event = new WeatherTriggerEvent();
break;
case Event::Type::Sign:
event = new SignEvent();
break;
case Event::Type::HiddenItem:
event = new HiddenItemEvent();
break;
case Event::Type::SecretBase:
event = new SecretBaseEvent();
break;
case Event::Type::HealLocation: {
event = new HealLocationEvent();
event->setMap(this->map);
event->setDefaultValues(this->project);
HealLocation healLocation = HealLocation::fromEvent(event);
project->healLocations.append(healLocation);
((HealLocationEvent *)event)->setIndex(project->healLocations.length());
break;
}
default:
break;
}
if (!event) return nullptr;
event->setMap(this->map);
event->setDefaultValues(this->project);
map->editHistory.push(new EventCreate(this, map, event));
return event->getPixmapItem();
}
return nullptr;
}
// Currently only object events have an explicit limit
bool Editor::eventLimitReached(QString event_type)
{
if (project && map && !event_type.isEmpty()) {
if (Event::typeToGroup(event_type) == EventGroup::Object)
return map->events.value(EventGroup::Object).length() >= project->getMaxObjectEvents();
bool Editor::eventLimitReached(Event::Type event_type) {
if (project && map) {
if (Event::typeToGroup(event_type) == Event::Group::Object)
return map->events.value(Event::Group::Object).length() >= project->getMaxObjectEvents();
}
return false;
}
void Editor::deleteEvent(Event *event) {
Map *map = project->getMap(event->get("map_name"));
if (map) {
map->removeEvent(event);
if (event->pixmapItem) {
events_group->removeFromGroup(event->pixmapItem);
delete event->pixmapItem;
event->pixmapItem = nullptr;
}
}
//selected_events->removeAll(event);
//updateSelectedObjects();
}
void Editor::openMapScripts() const {
const QString scriptPath = project->getMapScriptsFilePath(map->name);
openInTextEditor(scriptPath);

File diff suppressed because it is too large Load diff

View file

@ -212,7 +212,7 @@ bool Project::loadMapData(Map* map) {
map->sharedScriptsMap = ParseUtil::jsonToQString(mapObj["shared_scripts_map"]);
// Events
map->events[EventGroup::Object].clear();
map->events[Event::Group::Object].clear();
QJsonArray objectEventsArr = mapObj["object_events"].toArray();
bool hasCloneObjects = projectConfig.getEventCloneObjectEnabled();
for (int i = 0; i < objectEventsArr.size(); i++) {
@ -220,176 +220,100 @@ bool Project::loadMapData(Map* map) {
// 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());
object->put("x", QString::number(event["x"].toInt()));
object->put("y", QString::number(event["y"].toInt()));
object->put("elevation", QString::number(event["elevation"].toInt()));
object->put("movement_type", event["movement_type"].toString());
object->put("radius_x", QString::number(event["movement_range_x"].toInt()));
object->put("radius_y", QString::number(event["movement_range_y"].toInt()));
object->put("trainer_type", event["trainer_type"].toString());
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", EventGroup::Object);
map->events[EventGroup::Object].append(object);
ObjectEvent *object = new ObjectEvent();
object->loadFromJson(event, this);
map->addEvent(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));
CloneObjectEvent *clone = new CloneObjectEvent();
if (clone->loadFromJson(event, this)) {
map->addEvent(clone);
}
else {
delete clone;
}
} 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[EventGroup::Warp].clear();
map->events[Event::Group::Warp].clear();
QJsonArray warpEventsArr = mapObj["warp_events"].toArray();
for (int i = 0; i < warpEventsArr.size(); i++) {
QJsonObject event = warpEventsArr[i].toObject();
Event *warp = new Event(event, EventType::Warp);
warp->put("map_name", map->name);
warp->put("x", QString::number(event["x"].toInt()));
warp->put("y", QString::number(event["y"].toInt()));
warp->put("elevation", QString::number(event["elevation"].toInt()));
warp->put("destination_warp", QString::number(event["dest_warp_id"].toInt()));
// Ensure the warp destination map constant is valid before adding it to the warps.
QString mapConstant = event["dest_map"].toString();
if (mapConstantsToMapNames.contains(mapConstant)) {
warp->put("destination_map_name", mapConstantsToMapNames.value(mapConstant));
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", EventGroup::Warp);
map->events[EventGroup::Warp].append(warp);
} else {
logError(QString("Destination map constant '%1' is invalid for warp").arg(mapConstant));
WarpEvent *warp = new WarpEvent();
if (warp->loadFromJson(event, this)) {
map->addEvent(warp);
}
else {
delete warp;
}
}
map->events[EventGroup::Heal].clear();
for (auto it = healLocations.begin(); it != healLocations.end(); it++) {
HealLocation loc = *it;
//if TRUE map is flyable / has healing location
if (loc.mapName == QString(mapNamesToMapConstants.value(map->name)).remove(0,4)) {
Event *heal = new Event;
heal->put("map_name", map->name);
heal->put("x", loc.x);
heal->put("y", loc.y);
heal->put("loc_name", loc.mapName);
heal->put("id_name", loc.idName);
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", 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[EventGroup::Heal].append(heal);
}
}
map->events[EventGroup::Coord].clear();
map->events[Event::Group::Coord].clear();
QJsonArray coordEventsArr = mapObj["coord_events"].toArray();
for (int i = 0; i < coordEventsArr.size(); i++) {
QJsonObject event = coordEventsArr[i].toObject();
QString type = event["type"].toString();
if (type == "trigger") {
Event *coord = new Event(event, EventType::Trigger);
coord->put("map_name", map->name);
coord->put("x", QString::number(event["x"].toInt()));
coord->put("y", QString::number(event["y"].toInt()));
coord->put("elevation", QString::number(event["elevation"].toInt()));
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", EventGroup::Coord);
map->events[EventGroup::Coord].append(coord);
TriggerEvent *coord = new TriggerEvent();
coord->loadFromJson(event, this);
map->addEvent(coord);
} else if (type == "weather") {
Event *coord = new Event(event, EventType::WeatherTrigger);
coord->put("map_name", map->name);
coord->put("x", QString::number(event["x"].toInt()));
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", EventGroup::Coord);
coord->put("event_type", EventType::WeatherTrigger);
map->events[EventGroup::Coord].append(coord);
WeatherTriggerEvent *coord = new WeatherTriggerEvent();
coord->loadFromJson(event, this);
map->addEvent(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[EventGroup::Bg].clear();
map->events[Event::Group::Bg].clear();
QJsonArray bgEventsArr = mapObj["bg_events"].toArray();
for (int i = 0; i < bgEventsArr.size(); i++) {
QJsonObject event = bgEventsArr[i].toObject();
QString type = event["type"].toString();
if (type == "sign") {
Event *bg = new Event(event, EventType::Sign);
bg->put("map_name", map->name);
bg->put("x", QString::number(event["x"].toInt()));
bg->put("y", QString::number(event["y"].toInt()));
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", EventGroup::Bg);
map->events[EventGroup::Bg].append(bg);
SignEvent *bg = new SignEvent();
bg->loadFromJson(event, this);
map->addEvent(bg);
} else if (type == "hidden_item") {
Event *bg = new Event(event, EventType::HiddenItem);
bg->put("map_name", map->name);
bg->put("x", QString::number(event["x"].toInt()));
bg->put("y", QString::number(event["y"].toInt()));
bg->put("elevation", QString::number(event["elevation"].toInt()));
bg->put("item", event["item"].toString());
bg->put("flag", event["flag"].toString());
if (projectConfig.getHiddenItemQuantityEnabled()) {
bg->put("quantity", event["quantity"].toInt());
}
if (projectConfig.getHiddenItemRequiresItemfinderEnabled()) {
bg->put("underfoot", event["underfoot"].toBool());
}
bg->put("event_group_type", EventGroup::Bg);
map->events[EventGroup::Bg].append(bg);
HiddenItemEvent *bg = new HiddenItemEvent();
bg->loadFromJson(event, this);
map->addEvent(bg);
} else if (type == "secret_base") {
Event *bg = new Event(event, EventType::SecretBase);
bg->put("map_name", map->name);
bg->put("x", QString::number(event["x"].toInt()));
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", EventGroup::Bg);
map->events[EventGroup::Bg].append(bg);
SecretBaseEvent *bg = new SecretBaseEvent();
bg->loadFromJson(event, this);
map->addEvent(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));
}
}
map->events[Event::Group::Heal].clear();
for (auto it = healLocations.begin(); it != healLocations.end(); it++) {
HealLocation loc = *it;
//if TRUE map is flyable / has healing location
if (loc.mapName == QString(mapNamesToMapConstants.value(map->name)).remove(0,4)) {
HealLocationEvent *heal = new HealLocationEvent();
heal->setMap(map);
heal->setX(loc.x);
heal->setY(loc.y);
heal->setElevation(3);
heal->setLocationName(loc.mapName);
heal->setIdName(loc.idName);
heal->setIndex(loc.index);
// TODO: what is this
// heal->put("destination_map_name", mapConstantsToMapNames.value(map->name));
if (projectConfig.getHealLocationRespawnDataEnabled()) {
heal->setRespawnMap(mapConstantsToMapNames.value(QString("MAP_" + loc.respawnMap)));
heal->setRespawnNPC(loc.respawnNPC);
}
map->events[Event::Group::Heal].append(heal);
}
}
map->connections.clear();
QJsonArray connectionsArr = mapObj["connections"].toArray();
if (!connectionsArr.isEmpty()) {
@ -886,8 +810,8 @@ void Project::saveHealLocationStruct(Map *map) {
}
// set new location in healLocations list
if (map->events[EventGroup::Heal].length() > 0) {
for (Event *healEvent : map->events[EventGroup::Heal]) {
if (map->events[Event::Group::Heal].length() > 0) {
for (Event *healEvent : map->events[Event::Group::Heal]) {
HealLocation hl = HealLocation::fromEvent(healEvent);
healLocations[hl.index - 1] = hl;
}
@ -1360,9 +1284,9 @@ void Project::saveMap(Map *map) {
for (MapConnection* connection : map->connections) {
if (mapNamesToMapConstants.contains(connection->map_name)) {
OrderedJson::object connectionObj;
connectionObj["direction"] = connection->direction;
connectionObj["offset"] = connection->offset;
connectionObj["map"] = this->mapNamesToMapConstants.value(connection->map_name);
connectionObj["offset"] = connection->offset;
connectionObj["direction"] = connection->direction;
connectionsArr.append(connectionObj);
} else {
logError(QString("Failed to write map connection. '%1' is not a valid map name").arg(connection->map_name));
@ -1376,58 +1300,38 @@ void Project::saveMap(Map *map) {
if (map->sharedEventsMap.isEmpty()) {
// Object events
OrderedJson::array objectEventsArr;
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);
}
for (int i = 0; i < map->events[Event::Group::Object].length(); i++) {
Event *event = map->events[Event::Group::Object].value(i);
OrderedJson::object jsonObj = event->buildEventJson(this);
objectEventsArr.push_back(jsonObj);
}
mapObj["object_events"] = objectEventsArr;
// Warp events
OrderedJson::array warpEventsArr;
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);
for (int i = 0; i < map->events[Event::Group::Warp].length(); i++) {
Event *event = map->events[Event::Group::Warp].value(i);
OrderedJson::object warpObj = event->buildEventJson(this);
warpEventsArr.append(warpObj);
}
mapObj["warp_events"] = warpEventsArr;
// Coord events
OrderedJson::array coordEventsArr;
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();
for (int i = 0; i < map->events[Event::Group::Coord].length(); i++) {
Event *event = map->events[Event::Group::Coord].value(i);
OrderedJson::object triggerObj = event->buildEventJson(this);
coordEventsArr.append(triggerObj);
} else if (event_type == EventType::WeatherTrigger) {
OrderedJson::object weatherObj = event->buildWeatherTriggerEventJSON();
coordEventsArr.append(weatherObj);
}
}
mapObj["coord_events"] = coordEventsArr;
// Bg Events
OrderedJson::array bgEventsArr;
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();
bgEventsArr.append(signObj);
} else if (event_type == EventType::HiddenItem) {
OrderedJson::object hiddenItemObj = event->buildHiddenItemEventJSON();
bgEventsArr.append(hiddenItemObj);
} else if (event_type == EventType::SecretBase) {
OrderedJson::object secretBaseObj = event->buildSecretBaseEventJSON();
bgEventsArr.append(secretBaseObj);
}
for (int i = 0; i < map->events[Event::Group::Bg].length(); i++) {
Event *event = map->events[Event::Group::Bg].value(i);
OrderedJson::object bgObj = event->buildEventJson(this);
bgEventsArr.append(bgObj);
}
mapObj["bg_events"] = bgEventsArr;
} else {
@ -2378,6 +2282,10 @@ bool Project::readMiscellaneousConstants() {
return true;
}
QStringList Project::getGlobalScriptLabels() {
return this->eventScriptLabelModel.stringList();
}
bool Project::readEventScriptLabels() {
for (const auto &filePath : getEventScriptsFilePaths())
globalScriptLabels << ParseUtil::getGlobalScriptLabels(filePath);
@ -2460,58 +2368,9 @@ QCompleter *Project::getEventScriptLabelCompleter(QStringList additionalScriptLa
return &eventScriptLabelCompleter;
}
void Project::setEventPixmap(Event * event, bool forceLoad) {
if (!event || (!event->pixmap.isNull() && !forceLoad))
return;
event->spriteWidth = 16;
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::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(movement));
event->setPixmapFromSpritesheet(eventGfx->spritesheet, eventGfx->spriteWidth, eventGfx->spriteHeight, eventGfx->inanimate);
}
} else if (group_type == EventGroup::Warp) {
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(16, 0, 16, 16);
} else if (group_type == EventGroup::Coord) {
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(32, 0, 16, 16);
} else if (group_type == EventGroup::Bg) {
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(48, 0, 16, 16);
} else if (group_type == EventGroup::Heal) {
event->pixmap = QPixmap(":/images/Entities_16x16.png").copy(64, 0, 16, 16);
}
void Project::setEventPixmap(Event *event, bool forceLoad) {
if (event && (event->getPixmap().isNull() || forceLoad))
event->loadPixmap(this);
}
bool Project::readEventGraphics() {
@ -2600,8 +2459,8 @@ bool Project::readSpeciesIconPaths() {
void Project::saveMapHealEvents(Map *map) {
// save heal event changes
if (map->events[EventGroup::Heal].length() > 0) {
for (Event *healEvent : map->events[EventGroup::Heal]) {
if (map->events[Event::Group::Heal].length() > 0) {
for (Event *healEvent : map->events[Event::Group::Heal]) {
HealLocation hl = HealLocation::fromEvent(healEvent);
healLocations[hl.index - 1] = hl;
}
@ -2610,11 +2469,11 @@ void Project::saveMapHealEvents(Map *map) {
}
void Project::setNewMapEvents(Map *map) {
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();
map->events[Event::Group::Object].clear();
map->events[Event::Group::Warp].clear();
map->events[Event::Group::Heal].clear();
map->events[Event::Group::Coord].clear();
map->events[Event::Group::Bg].clear();
}
int Project::getNumTilesPrimary()

View file

@ -347,36 +347,44 @@ void MainWindow::setTilesetPalette(Tileset *tileset, int paletteIndex, QList<QLi
}
}
void MainWindow::setPrimaryTilesetPalette(int paletteIndex, QList<QList<int>> colors) {
void MainWindow::setPrimaryTilesetPalette(int paletteIndex, QList<QList<int>> colors, bool forceRedraw) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return;
this->setTilesetPalette(this->editor->map->layout->tileset_primary, paletteIndex, colors);
if (forceRedraw) {
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_primary);
}
}
void MainWindow::setPrimaryTilesetPalettes(QList<QList<QList<int>>> palettes) {
void MainWindow::setPrimaryTilesetPalettes(QList<QList<QList<int>>> palettes, bool forceRedraw) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return;
for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalette(this->editor->map->layout->tileset_primary, i, palettes[i]);
}
if (forceRedraw) {
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_primary);
}
}
void MainWindow::setSecondaryTilesetPalette(int paletteIndex, QList<QList<int>> colors) {
void MainWindow::setSecondaryTilesetPalette(int paletteIndex, QList<QList<int>> colors, bool forceRedraw) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return;
this->setTilesetPalette(this->editor->map->layout->tileset_secondary, paletteIndex, colors);
if (forceRedraw) {
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_secondary);
}
}
void MainWindow::setSecondaryTilesetPalettes(QList<QList<QList<int>>> palettes) {
void MainWindow::setSecondaryTilesetPalettes(QList<QList<QList<int>>> palettes, bool forceRedraw) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return;
for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalette(this->editor->map->layout->tileset_secondary, i, palettes[i]);
}
if (forceRedraw) {
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_secondary);
}
}
QJSValue MainWindow::getTilesetPalette(const QList<QList<QRgb>> &palettes, int paletteIndex) {
@ -449,36 +457,44 @@ void MainWindow::setTilesetPalettePreview(Tileset *tileset, int paletteIndex, QL
}
}
void MainWindow::setPrimaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors) {
void MainWindow::setPrimaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors, bool forceRedraw) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return;
this->setTilesetPalettePreview(this->editor->map->layout->tileset_primary, paletteIndex, colors);
if (forceRedraw) {
this->refreshAfterPalettePreviewChange();
}
}
void MainWindow::setPrimaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes) {
void MainWindow::setPrimaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes, bool forceRedraw) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return;
for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalettePreview(this->editor->map->layout->tileset_primary, i, palettes[i]);
}
if (forceRedraw) {
this->refreshAfterPalettePreviewChange();
}
}
void MainWindow::setSecondaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors) {
void MainWindow::setSecondaryTilesetPalettePreview(int paletteIndex, QList<QList<int>> colors, bool forceRedraw) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return;
this->setTilesetPalettePreview(this->editor->map->layout->tileset_secondary, paletteIndex, colors);
if (forceRedraw) {
this->refreshAfterPalettePreviewChange();
}
}
void MainWindow::setSecondaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes) {
void MainWindow::setSecondaryTilesetPalettesPreview(QList<QList<QList<int>>> palettes, bool forceRedraw) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return;
for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalettePreview(this->editor->map->layout->tileset_secondary, i, palettes[i]);
}
if (forceRedraw) {
this->refreshAfterPalettePreviewChange();
}
}
QJSValue MainWindow::getPrimaryTilesetPalettePreview(int paletteIndex) {

View file

@ -147,21 +147,95 @@ void MapView::setOpacity(int opacity) {
this->scene()->update();
}
qreal MapView::getHorizontalScale(int layer) {
return this->getOverlay(layer)->getHScale();
}
qreal MapView::getVerticalScale(int layer) {
return this->getOverlay(layer)->getVScale();
}
void MapView::setHorizontalScale(qreal scale, int layer) {
this->getOverlay(layer)->setHScale(scale);
this->scene()->update();
}
// Overload. No layer provided, set horizontal scale of all layers
void MapView::setHorizontalScale(qreal scale) {
foreach (Overlay * layer, this->overlayMap)
layer->setHScale(scale);
this->scene()->update();
}
void MapView::setVerticalScale(qreal scale, int layer) {
this->getOverlay(layer)->setVScale(scale);
this->scene()->update();
}
// Overload. No layer provided, set vertical scale of all layers
void MapView::setVerticalScale(qreal scale) {
foreach (Overlay * layer, this->overlayMap)
layer->setVScale(scale);
this->scene()->update();
}
int MapView::getRotation(int layer) {
return this->getOverlay(layer)->getRotation();
}
void MapView::setRotation(int angle, int layer) {
this->getOverlay(layer)->setRotation(angle);
this->scene()->update();
}
// Overload. No layer provided, set rotation of all layers
void MapView::setRotation(int angle) {
foreach (Overlay * layer, this->overlayMap)
layer->setRotation(angle);
this->scene()->update();
}
void MapView::rotate(int degrees, int layer) {
this->getOverlay(layer)->rotate(degrees);
this->scene()->update();
}
// Overload. No layer provided, rotate all layers
void MapView::rotate(int degrees) {
foreach (Overlay * layer, this->overlayMap)
layer->rotate(degrees);
this->scene()->update();
}
void MapView::addText(QString text, int x, int y, QString color, int fontSize, int layer) {
this->getOverlay(layer)->addText(text, x, y, color, fontSize);
this->scene()->update();
}
void MapView::addRect(int x, int y, int width, int height, QString color, int layer) {
this->getOverlay(layer)->addRect(x, y, width, height, color, false);
void MapView::addRect(int x, int y, int width, int height, QString borderColor, QString fillColor, int rounding, int layer) {
if (this->getOverlay(layer)->addRect(x, y, width, height, borderColor, fillColor, rounding))
this->scene()->update();
}
void MapView::addFilledRect(int x, int y, int width, int height, QString color, int layer) {
this->getOverlay(layer)->addRect(x, y, width, height, color, true);
void MapView::addPath(QList<int> xCoords, QList<int> yCoords, QString borderColor, QString fillColor, int layer) {
if (this->getOverlay(layer)->addPath(xCoords, yCoords, borderColor, fillColor))
this->scene()->update();
}
void MapView::addPath(QList<QList<int>> coords, QString borderColor, QString fillColor, int layer) {
QList<int> xCoords;
QList<int> yCoords;
for (int i = 0; i < coords.length(); i++) {
if (coords[i].length() < 2){
logWarn(QString("Element %1 of overlay path does not have an x and y value.").arg(i));
continue;
}
xCoords.append(coords[i][0]);
yCoords.append(coords[i][1]);
}
this->addPath(xCoords, yCoords, borderColor, fillColor, layer);
}
void MapView::addImage(int x, int y, QString filepath, int layer, bool useCache) {
if (this->getOverlay(layer)->addImage(x, y, filepath, useCache))
this->scene()->update();

View file

@ -33,7 +33,8 @@ CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) :
this->table->horizontalHeader()->setStretchLastSection(true);
layout->addWidget(this->table);
for (auto it = event->customValues.begin(); it != event->customValues.end(); it++) {
QMap<QString, QString> customValues = this->event->getCustomValues();
for (auto it = customValues.begin(); it != customValues.end(); it++) {
int rowIndex = this->table->rowCount();
this->table->insertRow(rowIndex);
this->table->setItem(rowIndex, 0, new QTableWidgetItem(it.key()));
@ -44,7 +45,7 @@ CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) :
int rowIndex = this->table->rowCount();
this->table->insertRow(rowIndex);
this->table->selectRow(rowIndex);
this->event->customValues = this->getTableFields();
this->event->setCustomValues(this->getTableFields());
this->resizeVertically();
});
@ -66,13 +67,13 @@ CustomAttributesTable::CustomAttributesTable(Event *event, QWidget *parent) :
this->table->selectRow(0);
}
this->event->customValues = this->getTableFields();
this->event->setCustomValues(this->getTableFields());
this->resizeVertically();
}
});
connect(this->table, &QTableWidget::cellChanged, [=]() {
this->event->customValues = this->getTableFields();
this->event->setCustomValues(this->getTableFields());
});
this->resizeVertically();

View file

@ -13,44 +13,23 @@ void DraggablePixmapItem::updatePosition() {
setX(x);
setY(y);
if (editor->selected_events && editor->selected_events->contains(this)) {
setZValue(event->y() + 1);
setZValue(event->getY() + 1);
} else {
setZValue(event->y());
setZValue(event->getY());
}
}
void DraggablePixmapItem::emitPositionChanged() {
emit xChanged(event->x());
emit yChanged(event->y());
emit elevationChanged(event->elevation());
emit xChanged(event->getX());
emit yChanged(event->getY());
emit elevationChanged(event->getElevation());
}
void DraggablePixmapItem::updatePixmap() {
editor->project->setEventPixmap(event, true);
this->updatePosition();
editor->redrawObject(this);
emit spriteChanged(event->pixmap);
}
void DraggablePixmapItem::bind(QComboBox *combo, QString key) {
connect(combo, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::currentTextChanged),
this, [this, key](QString value){
this->event->put(key, value);
});
connect(this, &DraggablePixmapItem::onPropertyChanged,
this, [combo, key](QString key2, QString value){
if (key2 == key) {
combo->addItem(value);
combo->setCurrentText(value);
}
});
}
void DraggablePixmapItem::bindToUserData(QComboBox *combo, QString key) {
connect(combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, [this, combo, key](int index) {
this->event->put(key, combo->itemData(index).toString());
});
emit spriteChanged(event->getPixmap());
}
void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) {
@ -63,8 +42,8 @@ void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) {
}
void DraggablePixmapItem::move(int dx, int dy) {
event->setX(event->x() + dx);
event->setY(event->y() + dy);
event->setX(event->getX() + dx);
event->setY(event->getY() + dy);
updatePosition();
emitPositionChanged();
}
@ -102,24 +81,27 @@ void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) {
}
void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
QString eventType = this->event->get("event_type");
if (eventType == EventType::Warp) {
QString destMap = this->event->get("destination_map_name");
Event::Type eventType = this->event->getEventType();
if (eventType == Event::Type::Warp) {
WarpEvent *warp = dynamic_cast<WarpEvent *>(this->event);
QString destMap = warp->getDestinationMap();
if (destMap != NONE_MAP_NAME) {
emit editor->warpEventDoubleClicked(destMap, this->event->get("destination_warp"), EventGroup::Warp);
emit editor->warpEventDoubleClicked(destMap, warp->getDestinationWarpID(), Event::Group::Warp);
}
}
else if (eventType == EventType::CloneObject) {
QString destMap = this->event->get("target_map");
else if (eventType == Event::Type::CloneObject) {
CloneObjectEvent *clone = dynamic_cast<CloneObjectEvent *>(this->event);
QString destMap = clone->getTargetMap();
if (destMap != NONE_MAP_NAME) {
emit editor->warpEventDoubleClicked(destMap, this->event->get("target_local_id"), EventGroup::Object);
emit editor->warpEventDoubleClicked(destMap, clone->getTargetID(), Event::Group::Object);
}
}
else if (eventType == EventType::SecretBase) {
QString baseId = this->event->get("secret_base_id");
else if (eventType == Event::Type::SecretBase) {
SecretBaseEvent *base = dynamic_cast<SecretBaseEvent *>(this->event);
QString baseId = base->getBaseID();
QString destMap = editor->project->mapConstantsToMapNames.value("MAP_" + baseId.left(baseId.lastIndexOf("_")));
if (destMap != NONE_MAP_NAME) {
emit editor->warpEventDoubleClicked(destMap, "0", EventGroup::Warp);
emit editor->warpEventDoubleClicked(destMap, 0, Event::Group::Warp);
}
}
}

1091
src/ui/eventframes.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,28 +0,0 @@
#include "eventpropertiesframe.h"
#include "customattributestable.h"
#include "ui_eventpropertiesframe.h"
EventPropertiesFrame::EventPropertiesFrame(Event *event, QWidget *parent) :
QFrame(parent),
ui(new Ui::EventPropertiesFrame)
{
ui->setupUi(this);
this->event = event;
this->firstShow = true;
}
EventPropertiesFrame::~EventPropertiesFrame()
{
delete ui;
}
void EventPropertiesFrame::paintEvent(QPaintEvent *painter) {
// Custom fields table.
if (firstShow && event->get("event_type") != EventType::HealLocation) {
CustomAttributesTable *customAttributes = new CustomAttributesTable(event, this);
this->layout()->addWidget(customAttributes);
}
QFrame::paintEvent(painter);
firstShow = false;
}

View file

@ -365,21 +365,6 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
pixmap = map->pixmap;
}
// draw events
QPainter eventPainter(&pixmap);
QList<Event*> events = map->getAllEvents();
for (Event *event : events) {
editor->project->setEventPixmap(event);
QString group = event->get("event_group_type");
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();
// draw map border
// note: this will break when allowing map to be selected from drop down maybe
int borderHeight = 0, borderWidth = 0;
@ -419,6 +404,21 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
connectionPainter.end();
}
// draw events
QPainter eventPainter(&pixmap);
QList<Event *> events = map->getAllEvents();
for (Event *event : events) {
editor->project->setEventPixmap(event);
Event::Group group = event->getEventGroup();
if ((showObjects && group == Event::Group::Object)
|| (showWarps && group == Event::Group::Warp)
|| (showBGs && group == Event::Group::Bg)
|| (showTriggers && group == Event::Group::Coord)
|| (showHealSpots && group == Event::Group::Heal))
eventPainter.drawImage(QPoint(event->getPixelX(), event->getPixelY()), event->getPixmap().toImage());
}
eventPainter.end();
// draw grid directly onto the pixmap
// since the last grid lines are outside of the pixmap, add a pixel to the bottom and right
if (showGrid) {

View file

@ -66,61 +66,61 @@ void NewEventToolButton::init()
this->setDefaultAction(this->newObjectAction);
}
QString NewEventToolButton::getSelectedEventType()
Event::Type NewEventToolButton::getSelectedEventType()
{
return this->selectedEventType;
}
void NewEventToolButton::newObject()
{
this->selectedEventType = EventType::Object;
this->selectedEventType = Event::Type::Object;
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newCloneObject()
{
this->selectedEventType = EventType::CloneObject;
this->selectedEventType = Event::Type::CloneObject;
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newWarp()
{
this->selectedEventType = EventType::Warp;
this->selectedEventType = Event::Type::Warp;
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newHealLocation()
{
this->selectedEventType = EventType::HealLocation;
this->selectedEventType = Event::Type::HealLocation;
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newTrigger()
{
this->selectedEventType = EventType::Trigger;
this->selectedEventType = Event::Type::Trigger;
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newWeatherTrigger()
{
this->selectedEventType = EventType::WeatherTrigger;
this->selectedEventType = Event::Type::WeatherTrigger;
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newSign()
{
this->selectedEventType = EventType::Sign;
this->selectedEventType = Event::Type::Sign;
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newHiddenItem()
{
this->selectedEventType = EventType::HiddenItem;
this->selectedEventType = Event::Type::HiddenItem;
emit newEventAdded(this->selectedEventType);
}
void NewEventToolButton::newSecretBase()
{
this->selectedEventType = EventType::SecretBase;
this->selectedEventType = Event::Type::SecretBase;
emit newEventAdded(this->selectedEventType);
}

View file

@ -1,5 +1,4 @@
#include "newmappopup.h"
#include "event.h"
#include "maplayout.h"
#include "mainwindow.h"
#include "ui_newmappopup.h"

View file

@ -2,44 +2,45 @@
#include "scripting.h"
#include "log.h"
void OverlayText::render(QPainter *painter, int x, int y) {
void OverlayText::render(QPainter *painter) {
QFont font = painter->font();
font.setPixelSize(this->fontSize);
painter->setFont(font);
painter->setPen(this->color);
painter->drawStaticText(this->x + x, this->y + y, this->text);
painter->drawStaticText(this->x, this->y, this->text);
}
void OverlayRect::render(QPainter *painter, int x, int y) {
if (this->filled) {
painter->fillRect(this->x + x, this->y + y, this->width, this->height, this->color);
} else {
painter->setPen(this->color);
painter->drawRect(this->x + x, this->y + y, this->width, this->height);
}
void OverlayPath::render(QPainter *painter) {
painter->fillPath(this->path, this->fillColor);
painter->setPen(this->borderColor);
painter->drawPath(this->path);
}
void OverlayImage::render(QPainter *painter, int x, int y) {
painter->drawImage(this->x + x, this->y + y, this->image);
void OverlayImage::render(QPainter *painter) {
painter->drawImage(this->x, this->y, this->image);
}
void Overlay::renderItems(QPainter *painter) {
if (this->hidden) return;
painter->save();
QTransform transform = painter->transform();
transform.translate(this->x, this->y);
transform.rotate(this->angle);
transform.scale(this->hScale, this->vScale);
painter->setTransform(transform);
if (this->clippingRect) {
painter->setClipping(true);
painter->setClipRect(*this->clippingRect);
}
qreal oldOpacity = painter->opacity();
painter->setOpacity(this->opacity);
for (auto item : this->items)
item->render(painter, this->x, this->y);
painter->setOpacity(oldOpacity);
item->render(painter);
if (this->clippingRect) {
painter->setClipping(false);
}
painter->restore();
}
void Overlay::clearItems() {
@ -67,7 +68,7 @@ int Overlay::getOpacity() {
void Overlay::setOpacity(int opacity) {
if (opacity < 0 || opacity > 100) {
logError(QString("Invalid overlay opacity '%1'").arg(opacity));
logError(QString("Invalid overlay opacity '%1', must be in range 0-100").arg(opacity));
return;
}
this->opacity = static_cast<qreal>(opacity) / 100;
@ -89,6 +90,44 @@ void Overlay::setY(int y) {
this->y = y;
}
qreal Overlay::getHScale() {
return this->hScale;
}
qreal Overlay::getVScale() {
return this->vScale;
}
void Overlay::setHScale(qreal scale) {
this->hScale = scale;
}
void Overlay::setVScale(qreal scale) {
this->vScale = scale;
}
int Overlay::getRotation() {
return this->angle;
}
void Overlay::setRotation(int angle) {
this->angle = angle;
this->clampAngle();
}
void Overlay::rotate(int degrees) {
this->angle += degrees;
this->clampAngle();
}
void Overlay::clampAngle() {
// transform.rotate would handle this already, but we only
// want to report angles 0-359 for Overlay::getRotation
this->angle %= 360;
if (this->angle < 0)
this->angle += 360;
}
void Overlay::setClippingRect(QRectF rect) {
if (this->clippingRect) {
delete this->clippingRect;
@ -113,12 +152,48 @@ void Overlay::move(int deltaX, int deltaY) {
this->y += deltaY;
}
void Overlay::addText(const QString text, int x, int y, QString color, int fontSize) {
this->items.append(new OverlayText(text, x, y, QColor(color), fontSize));
QColor Overlay::getColor(QString colorStr) {
if (colorStr.isEmpty())
colorStr = "transparent";
QColor color = QColor(colorStr);
if (!color.isValid()) {
logWarn(QString("Invalid overlay color \"%1\". Colors can be in the format \"#RRGGBB\" or \"#AARRGGBB\"").arg(colorStr));
color = QColor("transparent");
}
return color;
}
void Overlay::addRect(int x, int y, int width, int height, QString color, bool filled) {
this->items.append(new OverlayRect(x, y, width, height, QColor(color), filled));
void Overlay::addText(const QString text, int x, int y, QString colorStr, int fontSize) {
this->items.append(new OverlayText(text, x, y, getColor(colorStr), fontSize));
}
bool Overlay::addRect(int x, int y, int width, int height, QString borderColorStr, QString fillColorStr, int rounding) {
if (rounding < 0 || rounding > 100) {
logError(QString("Invalid rectangle rounding '%1', must be in range 0-100").arg(rounding));
return false;
}
QPainterPath path;
path.addRoundedRect(QRectF(x, y, width, height), rounding, rounding, Qt::RelativeSize);
this->items.append(new OverlayPath(path, getColor(borderColorStr), getColor(fillColorStr)));
return true;
}
bool Overlay::addPath(QList<int> xCoords, QList<int> yCoords, QString borderColorStr, QString fillColorStr) {
int numPoints = qMin(xCoords.length(), yCoords.length());
if (numPoints < 2) {
logError("Overlay path must have at least two points.");
return false;
}
QPainterPath path;
path.moveTo(xCoords.at(0), yCoords.at(0));
for (int i = 1; i < numPoints; i++)
path.lineTo(xCoords.at(i), yCoords.at(i));
this->items.append(new OverlayPath(path, getColor(borderColorStr), getColor(fillColorStr)));
return true;
}
bool Overlay::addImage(int x, int y, QString filepath, bool useCache, int width, int height, int xOffset, int yOffset, qreal hScale, qreal vScale, QList<QRgb> palette, bool setTransparency) {