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). - 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. - 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`. - 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 ### Added
- Add prefab support - Add prefab support
- Add Cut/Copy/Paste for metatiles in the Tileset Editor. - 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 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 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 option to not open the most recent project on launch.
- Add options for customizing how new maps are filled - Add options for customizing how new maps are filled
- Add color picker to palette editor for taking colors from the screen. - 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 ### Changed
- Overhauled the region map editor, adding support for tilemaps, and significant customization. Also now supports pokefirered. - 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. - 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 are preserved instead of being cleared.
- Unused metatile attribute bits that are set are preserved instead of being cleared.
- The wild encounter editor is automatically disabled if the encounter JSON data cannot be read - 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. - 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. - `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. - 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. - 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. - 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 ### Fixed
- Fix cursor tile outline not updating at the end of a dragged selection. - 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 collision values of 2 or 3 not rendering properly.
- Fix the map music dropdown being empty when importing a map from Advance Map. - 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. - 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 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. - 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. - 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 :param number paletteIndex: the palette index
:returns array: array of colors. Each color is a 3-element RGB array :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. 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 number paletteIndex: the palette index
:param array colors: array of colors. Each color is a 3-element RGB array :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() .. 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 :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. 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 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) .. 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 :param number paletteIndex: the palette index
:returns array: array of colors. Each color is a 3-element RGB array :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. 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 number paletteIndex: the palette index
:param array colors: array of colors. Each color is a 3-element RGB array :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() .. 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 :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. 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 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) .. 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 :param number paletteIndex: the palette index
:returns array: array of colors. Each color is a 3-element RGB array :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. 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 number paletteIndex: the palette index
:param array colors: array of colors. Each color is a 3-element RGB array :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() .. 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 :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. 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 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) .. 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 :param number paletteIndex: the palette index
:returns array: array of colors. Each color is a 3-element RGB array :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. 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 number paletteIndex: the palette index
:param array colors: array of colors. Each color is a 3-element RGB array :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() .. 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 :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. 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 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() .. js:function:: map.getMetatileLayerOrder()
@ -936,7 +944,7 @@ All tileset functions are callable via the global ``map`` object.
Overlay Functions 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. 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 :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) .. js:function:: overlay.getX(layer = 0)
Gets the x position of the specified overlay layer. 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 string text: the text to display
:param number x: the x pixel coordinate of the text (relative to the layer's position) :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 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 size: the font size of the text. Defaults to 12.
:param number layer: the layer id. Defaults to ``0`` :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. 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 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 width: the pixel width of the rectangle
:param number height: the pixel height 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`` :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 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 number y: the y pixel coordinate of the rectangle's top-left corner (relative to the layer's position) :param string borderColor: the color of the path. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to black.
:param number width: the pixel width of the rectangle :param string fillColor: the color of the area enclosed by the path. Can be specified as ``"#RRGGBB"`` or ``"#AARRGGBB"``. Defaults to transparent.
:param number height: the pixel height of the rectangle :param number layer: the layer id. Defaults to ``0``
:param string color: the color of the rectangle. Can be specified as "#RRGGBB" or "#AARRGGBB". Defaults to black.
.. 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`` :param number layer: the layer id. Defaults to ``0``
.. js:function:: overlay.addImage(x, y, filepath, layer = 0, useCache = true) .. js:function:: overlay.addImage(x, y, filepath, layer = 0, useCache = true)

View file

@ -813,8 +813,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>428</width> <width>423</width>
<height>77</height> <height>74</height>
</rect> </rect>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout_7"> <layout class="QHBoxLayout" name="horizontalLayout_7">
@ -1001,10 +1001,10 @@
</property> </property>
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>8</x>
<y>0</y> <y>0</y>
<width>411</width> <width>411</width>
<height>449</height> <height>413</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -1155,7 +1155,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>428</width> <width>428</width>
<height>704</height> <height>696</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="gridLayout_7"> <layout class="QGridLayout" name="gridLayout_7">
@ -1387,7 +1387,7 @@
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>330</width> <width>0</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
@ -1404,16 +1404,6 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>3</number> <number>3</number>
</property> </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"> <item row="0" column="0">
<widget class="QFrame" name="frame_4"> <widget class="QFrame" name="frame_4">
<property name="maximumSize"> <property name="maximumSize">
@ -1423,11 +1413,14 @@
</size> </size>
</property> </property>
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::StyledPanel</enum> <enum>QFrame::NoFrame</enum>
</property> </property>
<property name="frameShadow"> <property name="frameShadow">
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
@ -1522,8 +1515,24 @@
</layout> </layout>
</widget> </widget>
</item> </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"> <item row="2" column="0">
<widget class="QTabWidget" name="tabWidget_EventType"> <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"> <property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
@ -1544,8 +1553,57 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </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> <item>
<widget class="QScrollArea" name="scrollArea_Objects"> <widget class="QScrollArea" name="scrollArea_Objects">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable"> <property name="widgetResizable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -1557,8 +1615,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>98</width> <width>434</width>
<height>28</height> <height>581</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -1589,8 +1647,57 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </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> <item>
<widget class="QScrollArea" name="scrollArea_Warps"> <widget class="QScrollArea" name="scrollArea_Warps">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable"> <property name="widgetResizable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -1602,8 +1709,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>98</width> <width>434</width>
<height>28</height> <height>581</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -1634,8 +1741,57 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </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> <item>
<widget class="QScrollArea" name="scrollArea_Triggers"> <widget class="QScrollArea" name="scrollArea_Triggers">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable"> <property name="widgetResizable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -1647,8 +1803,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>98</width> <width>434</width>
<height>28</height> <height>581</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -1679,8 +1835,63 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </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> <item>
<widget class="QScrollArea" name="scrollArea_BGs"> <widget class="QScrollArea" name="scrollArea_BGs">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable"> <property name="widgetResizable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -1692,8 +1903,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>98</width> <width>434</width>
<height>28</height> <height>581</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -1724,8 +1935,57 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </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> <item>
<widget class="QScrollArea" name="scrollArea_Healspots"> <widget class="QScrollArea" name="scrollArea_Healspots">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable"> <property name="widgetResizable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -1737,8 +1997,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>98</width> <width>434</width>
<height>28</height> <height>581</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -1777,6 +2037,9 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable"> <property name="widgetResizable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@ -1788,8 +2051,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>98</width> <width>434</width>
<height>28</height> <height>625</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -2684,7 +2947,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1287</width> <width>1287</width>
<height>21</height> <height>22</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <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 #ifndef HEALLOCATION_H
#define HEALLOCATION_H #define HEALLOCATION_H
#include "event.h"
#include <QString> #include <QString>
#include <QDebug> #include <QDebug>
class Event;
class HealLocation { class HealLocation {
public: public:

View file

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

View file

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

View file

@ -158,7 +158,7 @@ public:
void undo() override; void undo() override;
void redo() 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; } int id() const override { return RMCommandId::ID_ClearEntries; }
private: private:

View file

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

View file

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

View file

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

View file

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

View file

@ -8,7 +8,7 @@
#include <QtWidgets> #include <QtWidgets>
#include "event.h" #include "events.h"
class Editor; class Editor;
@ -17,10 +17,10 @@ class DraggablePixmapItem : public QObject, public QGraphicsPixmapItem {
public: public:
DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {} DraggablePixmapItem(QPixmap pixmap): QGraphicsPixmapItem(pixmap) {}
DraggablePixmapItem(Event *event_, Editor *editor_) : QGraphicsPixmapItem(event_->pixmap) { DraggablePixmapItem(Event *event, Editor *editor) : QGraphicsPixmapItem(event->getPixmap()) {
event = event_; this->event = event;
event->setPixmapItem(this); event->setPixmapItem(this);
editor = editor_; this->editor = editor;
updatePosition(); updatePosition();
} }
@ -37,8 +37,6 @@ public:
void moveTo(const QPoint &pos); void moveTo(const QPoint &pos);
void emitPositionChanged(); void emitPositionChanged();
void updatePixmap(); void updatePixmap();
void bind(QComboBox *combo, QString key);
void bindToUserData(QComboBox *combo, QString key);
signals: signals:
void positionChanged(Event *event); void positionChanged(Event *event);
@ -49,25 +47,18 @@ signals:
void onPropertyChanged(QString key, QString value); void onPropertyChanged(QString key, QString value);
public slots: public slots:
void set_x(const QString &text) { void set_x(int x) {
event->put("x", text); event->setX(x);
updatePosition(); updatePosition();
} }
void set_y(const QString &text) { void set_y(int y) {
event->put("y", text); event->setY(y);
updatePosition(); updatePosition();
} }
void set_elevation(const QString &text) { void set_elevation(int z) {
event->put("elevation", text); event->setElevation(z);
updatePosition(); updatePosition();
} }
void set_sprite(const QString &text) {
event->put("sprite", text);
updatePixmap();
}
void set_script(const QString &text) {
event->put("script_label", text);
}
protected: protected:
void mousePressEvent(QGraphicsSceneMouseEvent*); 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 int getOpacity(int layer = 0);
Q_INVOKABLE void setOpacity(int opacity, int layer); Q_INVOKABLE void setOpacity(int opacity, int layer);
Q_INVOKABLE void setOpacity(int opacity); 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 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 addRect(int x, int y, int width, int height, QString borderColor = "#000000", QString fillColor = "transparent", int rounding = 0, int layer = 0);
Q_INVOKABLE void addFilledRect(int x, int y, int width, int height, QString color = "#000000", 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 addImage(int x, int y, QString filepath, int layer = 0, bool useCache = true);
Q_INVOKABLE void createImage(int x, int y, QString filepath, Q_INVOKABLE void createImage(int x, int y, QString filepath,
int width = -1, int height = -1, int xOffset = 0, int yOffset = 0, int width = -1, int height = -1, int xOffset = 0, int yOffset = 0,

View file

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

View file

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

View file

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

View file

@ -9,16 +9,16 @@
int getEventTypeMask(QList<Event *> events) { int getEventTypeMask(QList<Event *> events) {
int eventTypeMask = 0; int eventTypeMask = 0;
for (auto event : events) { for (auto event : events) {
QString groupType = event->get("event_group_type"); Event::Group groupType = event->getEventGroup();
if (groupType == EventGroup::Object) { if (groupType == Event::Group::Object) {
eventTypeMask |= IDMask_EventType_Object; eventTypeMask |= IDMask_EventType_Object;
} else if (groupType == EventGroup::Warp) { } else if (groupType == Event::Group::Warp) {
eventTypeMask |= IDMask_EventType_Warp; eventTypeMask |= IDMask_EventType_Warp;
} else if (groupType == EventGroup::Coord) { } else if (groupType == Event::Group::Coord) {
eventTypeMask |= IDMask_EventType_Trigger; eventTypeMask |= IDMask_EventType_Trigger;
} else if (groupType == EventGroup::Bg) { } else if (groupType == Event::Group::Bg) {
eventTypeMask |= IDMask_EventType_BG; eventTypeMask |= IDMask_EventType_BG;
} else if (groupType == EventGroup::Heal) { } else if (groupType == Event::Group::Heal) {
eventTypeMask |= IDMask_EventType_Heal; eventTypeMask |= IDMask_EventType_Heal;
} }
} }
@ -261,13 +261,13 @@ void EventMove::redo() {
QUndoCommand::redo(); QUndoCommand::redo();
for (Event *event : events) { for (Event *event : events) {
event->pixmapItem->move(deltaX, deltaY); event->getPixmapItem()->move(deltaX, deltaY);
} }
} }
void EventMove::undo() { void EventMove::undo() {
for (Event *event : events) { for (Event *event : events) {
event->pixmapItem->move(-deltaX, -deltaY); event->getPixmapItem()->move(-deltaX, -deltaY);
} }
QUndoCommand::undo(); QUndoCommand::undo();
@ -331,16 +331,16 @@ void EventCreate::redo() {
// select this event // select this event
editor->selected_events->clear(); editor->selected_events->clear();
editor->selectMapEvent(event->pixmapItem, false); editor->selectMapEvent(event->getPixmapItem(), false);
} }
void EventCreate::undo() { void EventCreate::undo() {
map->removeEvent(event); map->removeEvent(event);
if (editor->scene->items().contains(event->pixmapItem)) { if (editor->scene->items().contains(event->getPixmapItem())) {
editor->scene->removeItem(event->pixmapItem); editor->scene->removeItem(event->getPixmapItem());
} }
editor->selected_events->removeOne(event->pixmapItem); editor->selected_events->removeOne(event->getPixmapItem());
editor->shouldReselectEvents(); editor->shouldReselectEvents();
@ -377,15 +377,15 @@ void EventDelete::redo() {
for (Event *event : selectedEvents) { for (Event *event : selectedEvents) {
map->removeEvent(event); map->removeEvent(event);
if (editor->scene->items().contains(event->pixmapItem)) { if (editor->scene->items().contains(event->getPixmapItem())) {
editor->scene->removeItem(event->pixmapItem); editor->scene->removeItem(event->getPixmapItem());
} }
editor->selected_events->removeOne(event->pixmapItem); editor->selected_events->removeOne(event->getPixmapItem());
} }
editor->selected_events->clear(); editor->selected_events->clear();
if (nextSelectedEvent) if (nextSelectedEvent)
editor->selected_events->append(nextSelectedEvent->pixmapItem); editor->selected_events->append(nextSelectedEvent->getPixmapItem());
editor->shouldReselectEvents(); editor->shouldReselectEvents();
} }
@ -399,7 +399,7 @@ void EventDelete::undo() {
// select these events // select these events
editor->selected_events->clear(); editor->selected_events->clear();
for (Event *event : selectedEvents) { for (Event *event : selectedEvents) {
editor->selected_events->append(event->pixmapItem); editor->selected_events->append(event->getPixmapItem());
} }
editor->shouldReselectEvents(); editor->shouldReselectEvents();
@ -441,7 +441,7 @@ void EventDuplicate::redo() {
// select these events // select these events
editor->selected_events->clear(); editor->selected_events->clear();
for (Event *event : selectedEvents) { for (Event *event : selectedEvents) {
editor->selected_events->append(event->pixmapItem); editor->selected_events->append(event->getPixmapItem());
} }
editor->shouldReselectEvents(); editor->shouldReselectEvents();
} }
@ -450,10 +450,10 @@ void EventDuplicate::undo() {
for (Event *event : selectedEvents) { for (Event *event : selectedEvents) {
map->removeEvent(event); map->removeEvent(event);
if (editor->scene->items().contains(event->pixmapItem)) { if (editor->scene->items().contains(event->getPixmapItem())) {
editor->scene->removeItem(event->pixmapItem); editor->scene->removeItem(event->getPixmapItem());
} }
editor->selected_events->removeOne(event->pixmapItem); editor->selected_events->removeOne(event->getPixmapItem());
} }
editor->shouldReselectEvents(); editor->shouldReselectEvents();
@ -471,7 +471,7 @@ int EventDuplicate::id() const {
EventPaste::EventPaste(Editor *editor, Map *map, EventPaste::EventPaste(Editor *editor, Map *map,
QList<Event *> pastedEvents, QList<Event *> pastedEvents,
QUndoCommand *parent) : EventDuplicate(editor, map, pastedEvents) { QUndoCommand *parent) : EventDuplicate(editor, map, pastedEvents, parent) {
if (pastedEvents.size() > 1) { if (pastedEvents.size() > 1) {
setText("Paste Events"); setText("Paste Events");
} else { } 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 "heallocation.h"
#include "config.h" #include "config.h"
#include "events.h"
#include "map.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->idName = id;
this->mapName = map; this->mapName = map;
this->index = i; this->index = i;
@ -13,28 +15,23 @@ HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t
this->respawnNPC = respawnNPC; this->respawnNPC = respawnNPC;
} }
HealLocation HealLocation::fromEvent(Event *event) HealLocation HealLocation::fromEvent(Event *fromEvent) {
{ HealLocationEvent *event = dynamic_cast<HealLocationEvent *>(fromEvent);
HealLocation hl;
hl.idName = event->get("id_name"); HealLocation healLocation;
hl.mapName = event->get("loc_name"); healLocation.idName = event->getIdName();
try { healLocation.mapName = event->getLocationName();
hl.index = event->get("index").toInt(); healLocation.index = event->getIndex();
} healLocation.x = event->getX();
catch(...) { healLocation.y = event->getY();
hl.index = 0;
}
hl.x = event->getU16("x");
hl.y = event->getU16("y");
if (projectConfig.getHealLocationRespawnDataEnabled()) { if (projectConfig.getHealLocationRespawnDataEnabled()) {
hl.respawnNPC = event->getU16("respawn_npc"); healLocation.respawnNPC = event->getRespawnNPC();
hl.respawnMap = Map::mapConstantFromName(event->get("respawn_map")).remove(0,4); healLocation.respawnMap = Map::mapConstantFromName(event->getRespawnMap()).remove(0,4);
} }
return hl; return healLocation;
} }
QDebug operator<<(QDebug debug, const HealLocation &hl) QDebug operator<<(QDebug debug, const HealLocation &healLocation) {
{ debug << "HealLocation_" + healLocation.mapName << "(" << healLocation.x << ',' << healLocation.y << ")";
debug << "HealLocation_" + hl.mapName << "(" << hl.x << ',' << hl.y << ")";
return debug; return debug;
} }

View file

@ -340,6 +340,10 @@ void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata,
emit mapChanged(this); emit mapChanged(this);
} }
void Map::openScript(QString label) {
emit openScriptRequested(label);
}
bool Map::getBlock(int x, int y, Block *out) { bool Map::getBlock(int x, int y, Block *out) {
if (isWithinBounds(x, y)) { if (isWithinBounds(x, y)) {
int i = y * getWidth() + x; int i = y * getWidth() + x;
@ -474,37 +478,51 @@ QList<Event *> Map::getAllEvents() const {
return all_events; return all_events;
} }
QStringList Map::eventScriptLabels(const QString &event_group_type) const { QStringList Map::eventScriptLabels(Event::Group group) const {
QStringList scriptLabels; QStringList scriptLabels;
if (event_group_type.isEmpty()) {
for (const auto *event : getAllEvents()) if (group == Event::Group::None) {
scriptLabels << event->get("script_label"); ScriptTracker scriptTracker;
for (Event *event : this->getAllEvents()) {
event->accept(&scriptTracker);
}
scriptLabels = scriptTracker.getScripts();
} else { } else {
for (const auto *event : events.value(event_group_type)) ScriptTracker scriptTracker;
scriptLabels << event->get("script_label"); for (Event *event : events.value(group)) {
event->accept(&scriptTracker);
}
scriptLabels = scriptTracker.getScripts();
} }
scriptLabels.removeAll(""); scriptLabels.removeAll("");
scriptLabels.removeDuplicates(); scriptLabels.removeDuplicates();
if (scriptLabels.contains("0x0")) scriptLabels.prepend("0x0");
scriptLabels.move(scriptLabels.indexOf("0x0"), scriptLabels.count() - 1); scriptLabels.prepend("NULL");
if (scriptLabels.contains("NULL"))
scriptLabels.move(scriptLabels.indexOf("NULL"), scriptLabels.count() - 1);
return scriptLabels; return scriptLabels;
} }
void Map::removeEvent(Event *event) { void Map::removeEvent(Event *event) {
for (QString key : events.keys()) { for (Event::Group key : events.keys()) {
events[key].removeAll(event); events[key].removeAll(event);
} }
} }
void Map::addEvent(Event *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); if (!ownedEvents.contains(event)) ownedEvents.append(event);
} }
void Map::modify() {
emit modified();
}
void Map::clean() {
this->hasUnsavedDataChanges = false;
}
bool Map::hasUnsavedChanges() { bool Map::hasUnsavedChanges() {
return !editHistory.isClean() || hasUnsavedDataChanges || !isPersistedToFile; 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_globalPoryScriptLabel("\\b(script)(\\((global)\\))?\\s*\\b(?<label>[\\w_][\\w\\d_]*)");
const QRegularExpression ParseUtil::re_poryRawSection("\\b(raw)\\s*`(?<raw_script>[^`]*)"); const QRegularExpression ParseUtil::re_poryRawSection("\\b(raw)\\s*`(?<raw_script>[^`]*)");
using OrderedJson = poryjson::Json;
void ParseUtil::set_root(const QString &dir) { void ParseUtil::set_root(const QString &dir) {
this->root = dir; this->root = dir;
} }

View file

@ -268,14 +268,14 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
this->layout_array_label = label; this->layout_array_label = label;
QRegularExpression rowRe("{(?<row>[A-Z0-9_, ]+)}"); QRegularExpression rowRe("{(?<row>[A-Z0-9_, ]+)}");
QRegularExpressionMatchIterator j = rowRe.globalMatch(text); QRegularExpressionMatchIterator k = rowRe.globalMatch(text);
this->layout_layers.append("main"); this->layout_layers.append("main");
QList<LayoutSquare> layout; QList<LayoutSquare> layout;
int y = 0; int y = 0;
while (j.hasNext()) { while (k.hasNext()) {
QRegularExpressionMatch n = j.next(); QRegularExpressionMatch n = k.next();
QString row = n.captured("row"); QString row = n.captured("row");
QStringList rowSections = row.split(','); QStringList rowSections = row.split(',');
int x = 0; int x = 0;
@ -357,7 +357,7 @@ poryjson::Json::object RegionMap::config() {
layoutObject["height"] = this->layout_height; layoutObject["height"] = this->layout_height;
layoutObject["offset_left"] = this->offset_left; layoutObject["offset_left"] = this->offset_left;
layoutObject["offset_top"] = this->offset_top; 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["format"] = layoutFormatMap[this->layout_format];
layoutObject["path"] = this->layout_path; layoutObject["path"] = this->layout_path;
config["layout"] = layoutObject; config["layout"] = layoutObject;
@ -405,11 +405,26 @@ void RegionMap::saveLayout() {
} }
text += " = {\n"; text += " = {\n";
if (this->layout_layers.size() == 1) { if (this->layout_layers.size() == 1) {
if (this->layout_constants.count() == 1) {
for (LayoutSquare s : this->getLayout("main")) { for (LayoutSquare s : this->getLayout("main")) {
text += " " + s.map_section + ",\n"; text += " " + s.map_section + ",\n";
} }
text.chop(2); text.chop(2);
text += "\n"; 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 { } else {
// multi layered // multi layered
for (auto layoutName : this->layout_layers) { 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"); setText("Clear Entries");
this->map = map; this->map = map;

View file

@ -1,6 +1,5 @@
#include "editor.h" #include "editor.h"
#include "draggablepixmapitem.h" #include "draggablepixmapitem.h"
#include "event.h"
#include "imageproviders.h" #include "imageproviders.h"
#include "log.h" #include "log.h"
#include "mapconnection.h" #include "mapconnection.h"
@ -1093,6 +1092,12 @@ bool Editor::setMap(QString map_name) {
return false; 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) { if (project) {
Map *loadedMap = project->loadMap(map_name); Map *loadedMap = project->loadMap(map_name);
if (!loadedMap) { if (!loadedMap) {
@ -1109,6 +1114,7 @@ bool Editor::setMap(QString map_name) {
} }
map_ruler->setMapDimensions(QSize(map->getWidth(), map->getHeight())); map_ruler->setMapDimensions(QSize(map->getWidth(), map->getHeight()));
connect(map, &Map::mapDimensionsChanged, map_ruler, &MapRuler::setMapDimensions); connect(map, &Map::mapDimensionsChanged, map_ruler, &MapRuler::setMapDimensions);
connect(map, &Map::openScriptRequested, this, &Editor::openScript);
updateSelectedEvents(); updateSelectedEvents();
} }
@ -1230,11 +1236,11 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item
// Left-clicking while in paint mode will add a new event of the // Left-clicking while in paint mode will add a new event of the
// type of the first currently selected events. // type of the first currently selected events.
// Disallow adding heal locations, deleting them is not possible yet // 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) 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) { if (eventType != Event::Type::HealLocation) {
DraggablePixmapItem *newEvent = addNewEvent(eventType); DraggablePixmapItem *newEvent = addNewEvent(eventType);
if (newEvent) { if (newEvent) {
newEvent->move(pos.x(), pos.y()); newEvent->move(pos.x(), pos.y());
@ -1250,7 +1256,6 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item
static unsigned actionId = 0; static unsigned actionId = 0;
if (event->type() == QEvent::GraphicsSceneMouseRelease) { if (event->type() == QEvent::GraphicsSceneMouseRelease) {
// TODO: commit / update history here
actionId++; actionId++;
} else { } else {
if (event->type() == QEvent::GraphicsSceneMousePress) { if (event->type() == QEvent::GraphicsSceneMousePress) {
@ -1516,7 +1521,6 @@ void Editor::displayMapEvents() {
DraggablePixmapItem *Editor::addMapEvent(Event *event) { DraggablePixmapItem *Editor::addMapEvent(Event *event) {
DraggablePixmapItem *object = new DraggablePixmapItem(event, this); DraggablePixmapItem *object = new DraggablePixmapItem(event, this);
event->setPixmapItem(object);
this->redrawObject(object); this->redrawObject(object);
events_group->addToGroup(object); events_group->addToGroup(object);
return object; return object;
@ -1999,15 +2003,16 @@ QList<DraggablePixmapItem *> Editor::getObjects() {
} }
void Editor::redrawObject(DraggablePixmapItem *item) { void Editor::redrawObject(DraggablePixmapItem *item) {
if (item && item->event && !item->event->pixmap.isNull()) { if (item && item->event && !item->event->getPixmap().isNull()) {
qreal opacity = item->event->usingSprite ? 1.0 : 0.7; qreal opacity = item->event->getUsingSprite() ? 1.0 : 0.7;
item->setOpacity(opacity); 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); item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
if (selected_events && selected_events->contains(item)) { if (selected_events && selected_events->contains(item)) {
QImage image = item->pixmap().toImage(); QImage image = item->pixmap().toImage();
QPainter painter(&image); 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.drawRect(0, 0, image.width() - 1, image.height() - 1);
painter.end(); painter.end();
item->setPixmap(QPixmap::fromImage(image)); item->setPixmap(QPixmap::fromImage(image));
@ -2025,7 +2030,7 @@ void Editor::updateSelectedEvents() {
redrawObject(item); redrawObject(item);
} }
emit selectedObjectsChanged(); emit objectsChanged();
} }
void Editor::selectMapEvent(DraggablePixmapItem *object) { 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() { void Editor::duplicateSelectedEvents() {
if (!selected_events || !selected_events->length() || !map || !current_view || map_item->paintingMode != MapPixmapItem::PaintMode::EventObjects) if (!selected_events || !selected_events->length() || !map || !current_view || map_item->paintingMode != MapPixmapItem::PaintMode::EventObjects)
return; return;
@ -2055,60 +2083,89 @@ void Editor::duplicateSelectedEvents() {
QList<Event *> selectedEvents; QList<Event *> selectedEvents;
for (int i = 0; i < selected_events->length(); i++) { for (int i = 0; i < selected_events->length(); i++) {
Event *original = selected_events->at(i)->event; Event *original = selected_events->at(i)->event;
QString eventType = original->get("event_type"); Event::Type eventType = original->getEventType();
if (eventLimitReached(eventType)) { 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; continue;
} }
if (eventType == EventType::HealLocation) continue; if (eventType == Event::Type::HealLocation) {
Event *duplicate = new Event(*original); logWarn("Skipping duplication, event is a heal location.");
duplicate->setX(duplicate->x() + 1); continue;
duplicate->setY(duplicate->y() + 1); }
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); selectedEvents.append(duplicate);
} }
map->editHistory.push(new EventDuplicate(this, map, selectedEvents)); map->editHistory.push(new EventDuplicate(this, map, selectedEvents));
} }
DraggablePixmapItem* Editor::addNewEvent(QString event_type) { DraggablePixmapItem *Editor::addNewEvent(Event::Type type) {
if (project && map && !event_type.isEmpty() && !eventLimitReached(event_type)) { Event *event = nullptr;
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));
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; return nullptr;
} }
// Currently only object events have an explicit limit // Currently only object events have an explicit limit
bool Editor::eventLimitReached(QString event_type) bool Editor::eventLimitReached(Event::Type event_type) {
{ if (project && map) {
if (project && map && !event_type.isEmpty()) { if (Event::typeToGroup(event_type) == Event::Group::Object)
if (Event::typeToGroup(event_type) == EventGroup::Object) return map->events.value(Event::Group::Object).length() >= project->getMaxObjectEvents();
return map->events.value(EventGroup::Object).length() >= project->getMaxObjectEvents();
} }
return false; 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 { void Editor::openMapScripts() const {
const QString scriptPath = project->getMapScriptsFilePath(map->name); const QString scriptPath = project->getMapScriptsFilePath(map->name);
openInTextEditor(scriptPath); 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"]); map->sharedScriptsMap = ParseUtil::jsonToQString(mapObj["shared_scripts_map"]);
// Events // Events
map->events[EventGroup::Object].clear(); map->events[Event::Group::Object].clear();
QJsonArray objectEventsArr = mapObj["object_events"].toArray(); QJsonArray objectEventsArr = mapObj["object_events"].toArray();
bool hasCloneObjects = projectConfig.getEventCloneObjectEnabled(); bool hasCloneObjects = projectConfig.getEventCloneObjectEnabled();
for (int i = 0; i < objectEventsArr.size(); i++) { 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 // If clone objects are not enabled then no type field is present
QString type = hasCloneObjects ? event["type"].toString() : "object"; QString type = hasCloneObjects ? event["type"].toString() : "object";
if (type.isEmpty() || type == "object") { if (type.isEmpty() || type == "object") {
Event *object = new Event(event, EventType::Object); ObjectEvent *object = new ObjectEvent();
object->put("map_name", map->name); object->loadFromJson(event, this);
object->put("sprite", event["graphics_id"].toString()); map->addEvent(object);
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);
} else if (type == "clone") { } else if (type == "clone") {
Event *object = new Event(event, EventType::CloneObject); CloneObjectEvent *clone = new CloneObjectEvent();
object->put("map_name", map->name); if (clone->loadFromJson(event, this)) {
object->put("sprite", event["graphics_id"].toString()); map->addEvent(clone);
object->put("x", QString::number(event["x"].toInt())); }
object->put("y", QString::number(event["y"].toInt())); else {
object->put("target_local_id", QString::number(event["target_local_id"].toInt())); delete clone;
// Ensure the target map constant is valid before adding it to the events.
QString mapConstant = event["target_map"].toString();
if (mapConstantsToMapNames.contains(mapConstant)) {
object->put("target_map", mapConstantsToMapNames.value(mapConstant));
object->put("event_group_type", EventGroup::Object);
map->events[EventGroup::Object].append(object);
} else if (mapConstant == NONE_MAP_CONSTANT) {
object->put("target_map", NONE_MAP_NAME);
object->put("event_group_type", EventGroup::Object);
map->events[EventGroup::Object].append(object);
} else {
logError(QString("Destination map constant '%1' is invalid").arg(mapConstant));
} }
} else { } else {
logError(QString("Map %1 object_event %2 has invalid type '%3'. Must be 'object' or 'clone'.").arg(map->name).arg(i).arg(type)); 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(); QJsonArray warpEventsArr = mapObj["warp_events"].toArray();
for (int i = 0; i < warpEventsArr.size(); i++) { for (int i = 0; i < warpEventsArr.size(); i++) {
QJsonObject event = warpEventsArr[i].toObject(); QJsonObject event = warpEventsArr[i].toObject();
Event *warp = new Event(event, EventType::Warp); WarpEvent *warp = new WarpEvent();
warp->put("map_name", map->name); if (warp->loadFromJson(event, this)) {
warp->put("x", QString::number(event["x"].toInt())); map->addEvent(warp);
warp->put("y", QString::number(event["y"].toInt())); }
warp->put("elevation", QString::number(event["elevation"].toInt())); else {
warp->put("destination_warp", QString::number(event["dest_warp_id"].toInt())); delete warp;
// 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));
} }
} }
map->events[EventGroup::Heal].clear(); map->events[Event::Group::Coord].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();
QJsonArray coordEventsArr = mapObj["coord_events"].toArray(); QJsonArray coordEventsArr = mapObj["coord_events"].toArray();
for (int i = 0; i < coordEventsArr.size(); i++) { for (int i = 0; i < coordEventsArr.size(); i++) {
QJsonObject event = coordEventsArr[i].toObject(); QJsonObject event = coordEventsArr[i].toObject();
QString type = event["type"].toString(); QString type = event["type"].toString();
if (type == "trigger") { if (type == "trigger") {
Event *coord = new Event(event, EventType::Trigger); TriggerEvent *coord = new TriggerEvent();
coord->put("map_name", map->name); coord->loadFromJson(event, this);
coord->put("x", QString::number(event["x"].toInt())); map->addEvent(coord);
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);
} else if (type == "weather") { } else if (type == "weather") {
Event *coord = new Event(event, EventType::WeatherTrigger); WeatherTriggerEvent *coord = new WeatherTriggerEvent();
coord->put("map_name", map->name); coord->loadFromJson(event, this);
coord->put("x", QString::number(event["x"].toInt())); map->addEvent(coord);
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);
} else { } else {
logError(QString("Map %1 coord_event %2 has invalid type '%3'. Must be 'trigger' or 'weather'.").arg(map->name).arg(i).arg(type)); 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(); QJsonArray bgEventsArr = mapObj["bg_events"].toArray();
for (int i = 0; i < bgEventsArr.size(); i++) { for (int i = 0; i < bgEventsArr.size(); i++) {
QJsonObject event = bgEventsArr[i].toObject(); QJsonObject event = bgEventsArr[i].toObject();
QString type = event["type"].toString(); QString type = event["type"].toString();
if (type == "sign") { if (type == "sign") {
Event *bg = new Event(event, EventType::Sign); SignEvent *bg = new SignEvent();
bg->put("map_name", map->name); bg->loadFromJson(event, this);
bg->put("x", QString::number(event["x"].toInt())); map->addEvent(bg);
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);
} else if (type == "hidden_item") { } else if (type == "hidden_item") {
Event *bg = new Event(event, EventType::HiddenItem); HiddenItemEvent *bg = new HiddenItemEvent();
bg->put("map_name", map->name); bg->loadFromJson(event, this);
bg->put("x", QString::number(event["x"].toInt())); map->addEvent(bg);
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);
} else if (type == "secret_base") { } else if (type == "secret_base") {
Event *bg = new Event(event, EventType::SecretBase); SecretBaseEvent *bg = new SecretBaseEvent();
bg->put("map_name", map->name); bg->loadFromJson(event, this);
bg->put("x", QString::number(event["x"].toInt())); map->addEvent(bg);
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);
} else { } 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)); 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(); map->connections.clear();
QJsonArray connectionsArr = mapObj["connections"].toArray(); QJsonArray connectionsArr = mapObj["connections"].toArray();
if (!connectionsArr.isEmpty()) { if (!connectionsArr.isEmpty()) {
@ -886,8 +810,8 @@ void Project::saveHealLocationStruct(Map *map) {
} }
// set new location in healLocations list // set new location in healLocations list
if (map->events[EventGroup::Heal].length() > 0) { if (map->events[Event::Group::Heal].length() > 0) {
for (Event *healEvent : map->events[EventGroup::Heal]) { for (Event *healEvent : map->events[Event::Group::Heal]) {
HealLocation hl = HealLocation::fromEvent(healEvent); HealLocation hl = HealLocation::fromEvent(healEvent);
healLocations[hl.index - 1] = hl; healLocations[hl.index - 1] = hl;
} }
@ -1360,9 +1284,9 @@ void Project::saveMap(Map *map) {
for (MapConnection* connection : map->connections) { for (MapConnection* connection : map->connections) {
if (mapNamesToMapConstants.contains(connection->map_name)) { if (mapNamesToMapConstants.contains(connection->map_name)) {
OrderedJson::object connectionObj; OrderedJson::object connectionObj;
connectionObj["direction"] = connection->direction;
connectionObj["offset"] = connection->offset;
connectionObj["map"] = this->mapNamesToMapConstants.value(connection->map_name); connectionObj["map"] = this->mapNamesToMapConstants.value(connection->map_name);
connectionObj["offset"] = connection->offset;
connectionObj["direction"] = connection->direction;
connectionsArr.append(connectionObj); connectionsArr.append(connectionObj);
} else { } else {
logError(QString("Failed to write map connection. '%1' is not a valid map name").arg(connection->map_name)); logError(QString("Failed to write map connection. '%1' is not a valid map name").arg(connection->map_name));
@ -1376,58 +1300,38 @@ void Project::saveMap(Map *map) {
if (map->sharedEventsMap.isEmpty()) { if (map->sharedEventsMap.isEmpty()) {
// Object events // Object events
OrderedJson::array objectEventsArr; OrderedJson::array objectEventsArr;
for (int i = 0; i < map->events[EventGroup::Object].length(); i++) { for (int i = 0; i < map->events[Event::Group::Object].length(); i++) {
Event *event = map->events[EventGroup::Object].value(i); Event *event = map->events[Event::Group::Object].value(i);
QString event_type = event->get("event_type"); OrderedJson::object jsonObj = event->buildEventJson(this);
OrderedJson::object jsonObj;
if (event_type == EventType::Object) {
jsonObj = event->buildObjectEventJSON();
} else if (event_type == EventType::CloneObject) {
jsonObj = event->buildCloneObjectEventJSON(mapNamesToMapConstants);
}
objectEventsArr.push_back(jsonObj); objectEventsArr.push_back(jsonObj);
} }
mapObj["object_events"] = objectEventsArr; mapObj["object_events"] = objectEventsArr;
// Warp events // Warp events
OrderedJson::array warpEventsArr; OrderedJson::array warpEventsArr;
for (int i = 0; i < map->events[EventGroup::Warp].length(); i++) { for (int i = 0; i < map->events[Event::Group::Warp].length(); i++) {
Event *warp_event = map->events[EventGroup::Warp].value(i); Event *event = map->events[Event::Group::Warp].value(i);
OrderedJson::object warpObj = warp_event->buildWarpEventJSON(mapNamesToMapConstants); OrderedJson::object warpObj = event->buildEventJson(this);
warpEventsArr.append(warpObj); warpEventsArr.append(warpObj);
} }
mapObj["warp_events"] = warpEventsArr; mapObj["warp_events"] = warpEventsArr;
// Coord events // Coord events
OrderedJson::array coordEventsArr; OrderedJson::array coordEventsArr;
for (int i = 0; i < map->events[EventGroup::Coord].length(); i++) { for (int i = 0; i < map->events[Event::Group::Coord].length(); i++) {
Event *event = map->events[EventGroup::Coord].value(i); Event *event = map->events[Event::Group::Coord].value(i);
QString event_type = event->get("event_type"); OrderedJson::object triggerObj = event->buildEventJson(this);
if (event_type == EventType::Trigger) {
OrderedJson::object triggerObj = event->buildTriggerEventJSON();
coordEventsArr.append(triggerObj); coordEventsArr.append(triggerObj);
} else if (event_type == EventType::WeatherTrigger) {
OrderedJson::object weatherObj = event->buildWeatherTriggerEventJSON();
coordEventsArr.append(weatherObj);
}
} }
mapObj["coord_events"] = coordEventsArr; mapObj["coord_events"] = coordEventsArr;
// Bg Events // Bg Events
OrderedJson::array bgEventsArr; OrderedJson::array bgEventsArr;
for (int i = 0; i < map->events[EventGroup::Bg].length(); i++) { for (int i = 0; i < map->events[Event::Group::Bg].length(); i++) {
Event *event = map->events[EventGroup::Bg].value(i); Event *event = map->events[Event::Group::Bg].value(i);
QString event_type = event->get("event_type"); OrderedJson::object bgObj = event->buildEventJson(this);
if (event_type == EventType::Sign) { bgEventsArr.append(bgObj);
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);
}
} }
mapObj["bg_events"] = bgEventsArr; mapObj["bg_events"] = bgEventsArr;
} else { } else {
@ -2378,6 +2282,10 @@ bool Project::readMiscellaneousConstants() {
return true; return true;
} }
QStringList Project::getGlobalScriptLabels() {
return this->eventScriptLabelModel.stringList();
}
bool Project::readEventScriptLabels() { bool Project::readEventScriptLabels() {
for (const auto &filePath : getEventScriptsFilePaths()) for (const auto &filePath : getEventScriptsFilePaths())
globalScriptLabels << ParseUtil::getGlobalScriptLabels(filePath); globalScriptLabels << ParseUtil::getGlobalScriptLabels(filePath);
@ -2461,57 +2369,8 @@ QCompleter *Project::getEventScriptLabelCompleter(QStringList additionalScriptLa
} }
void Project::setEventPixmap(Event *event, bool forceLoad) { void Project::setEventPixmap(Event *event, bool forceLoad) {
if (!event || (!event->pixmap.isNull() && !forceLoad)) if (event && (event->getPixmap().isNull() || forceLoad))
return; event->loadPixmap(this);
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);
}
} }
bool Project::readEventGraphics() { bool Project::readEventGraphics() {
@ -2600,8 +2459,8 @@ bool Project::readSpeciesIconPaths() {
void Project::saveMapHealEvents(Map *map) { void Project::saveMapHealEvents(Map *map) {
// save heal event changes // save heal event changes
if (map->events[EventGroup::Heal].length() > 0) { if (map->events[Event::Group::Heal].length() > 0) {
for (Event *healEvent : map->events[EventGroup::Heal]) { for (Event *healEvent : map->events[Event::Group::Heal]) {
HealLocation hl = HealLocation::fromEvent(healEvent); HealLocation hl = HealLocation::fromEvent(healEvent);
healLocations[hl.index - 1] = hl; healLocations[hl.index - 1] = hl;
} }
@ -2610,11 +2469,11 @@ void Project::saveMapHealEvents(Map *map) {
} }
void Project::setNewMapEvents(Map *map) { void Project::setNewMapEvents(Map *map) {
map->events[EventGroup::Object].clear(); map->events[Event::Group::Object].clear();
map->events[EventGroup::Warp].clear(); map->events[Event::Group::Warp].clear();
map->events[EventGroup::Heal].clear(); map->events[Event::Group::Heal].clear();
map->events[EventGroup::Coord].clear(); map->events[Event::Group::Coord].clear();
map->events[EventGroup::Bg].clear(); map->events[Event::Group::Bg].clear();
} }
int Project::getNumTilesPrimary() int Project::getNumTilesPrimary()

View file

@ -347,37 +347,45 @@ 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) if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return; return;
this->setTilesetPalette(this->editor->map->layout->tileset_primary, paletteIndex, colors); this->setTilesetPalette(this->editor->map->layout->tileset_primary, paletteIndex, colors);
if (forceRedraw) {
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_primary); 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) if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return; return;
for (int i = 0; i < palettes.size(); i++) { for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalette(this->editor->map->layout->tileset_primary, i, palettes[i]); this->setTilesetPalette(this->editor->map->layout->tileset_primary, i, palettes[i]);
} }
if (forceRedraw) {
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_primary); 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) if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return; return;
this->setTilesetPalette(this->editor->map->layout->tileset_secondary, paletteIndex, colors); this->setTilesetPalette(this->editor->map->layout->tileset_secondary, paletteIndex, colors);
if (forceRedraw) {
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_secondary); 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) if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return; return;
for (int i = 0; i < palettes.size(); i++) { for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalette(this->editor->map->layout->tileset_secondary, i, palettes[i]); this->setTilesetPalette(this->editor->map->layout->tileset_secondary, i, palettes[i]);
} }
if (forceRedraw) {
this->refreshAfterPaletteChange(this->editor->map->layout->tileset_secondary); this->refreshAfterPaletteChange(this->editor->map->layout->tileset_secondary);
} }
}
QJSValue MainWindow::getTilesetPalette(const QList<QList<QRgb>> &palettes, int paletteIndex) { QJSValue MainWindow::getTilesetPalette(const QList<QList<QRgb>> &palettes, int paletteIndex) {
if (paletteIndex >= palettes.size()) if (paletteIndex >= palettes.size())
@ -449,37 +457,45 @@ 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) if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return; return;
this->setTilesetPalettePreview(this->editor->map->layout->tileset_primary, paletteIndex, colors); this->setTilesetPalettePreview(this->editor->map->layout->tileset_primary, paletteIndex, colors);
if (forceRedraw) {
this->refreshAfterPalettePreviewChange(); 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) if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)
return; return;
for (int i = 0; i < palettes.size(); i++) { for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalettePreview(this->editor->map->layout->tileset_primary, i, palettes[i]); this->setTilesetPalettePreview(this->editor->map->layout->tileset_primary, i, palettes[i]);
} }
if (forceRedraw) {
this->refreshAfterPalettePreviewChange(); 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) if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return; return;
this->setTilesetPalettePreview(this->editor->map->layout->tileset_secondary, paletteIndex, colors); this->setTilesetPalettePreview(this->editor->map->layout->tileset_secondary, paletteIndex, colors);
if (forceRedraw) {
this->refreshAfterPalettePreviewChange(); 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) if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_secondary)
return; return;
for (int i = 0; i < palettes.size(); i++) { for (int i = 0; i < palettes.size(); i++) {
this->setTilesetPalettePreview(this->editor->map->layout->tileset_secondary, i, palettes[i]); this->setTilesetPalettePreview(this->editor->map->layout->tileset_secondary, i, palettes[i]);
} }
if (forceRedraw) {
this->refreshAfterPalettePreviewChange(); this->refreshAfterPalettePreviewChange();
} }
}
QJSValue MainWindow::getPrimaryTilesetPalettePreview(int paletteIndex) { QJSValue MainWindow::getPrimaryTilesetPalettePreview(int paletteIndex) {
if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary) if (!this->editor || !this->editor->map || !this->editor->map->layout || !this->editor->map->layout->tileset_primary)

View file

@ -147,21 +147,95 @@ void MapView::setOpacity(int opacity) {
this->scene()->update(); 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) { 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->getOverlay(layer)->addText(text, x, y, color, fontSize);
this->scene()->update(); this->scene()->update();
} }
void MapView::addRect(int x, int y, int width, int height, QString color, int layer) { void MapView::addRect(int x, int y, int width, int height, QString borderColor, QString fillColor, int rounding, int layer) {
this->getOverlay(layer)->addRect(x, y, width, height, color, false); if (this->getOverlay(layer)->addRect(x, y, width, height, borderColor, fillColor, rounding))
this->scene()->update(); this->scene()->update();
} }
void MapView::addFilledRect(int x, int y, int width, int height, QString color, int layer) { void MapView::addPath(QList<int> xCoords, QList<int> yCoords, QString borderColor, QString fillColor, int layer) {
this->getOverlay(layer)->addRect(x, y, width, height, color, true); if (this->getOverlay(layer)->addPath(xCoords, yCoords, borderColor, fillColor))
this->scene()->update(); 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) { void MapView::addImage(int x, int y, QString filepath, int layer, bool useCache) {
if (this->getOverlay(layer)->addImage(x, y, filepath, useCache)) if (this->getOverlay(layer)->addImage(x, y, filepath, useCache))
this->scene()->update(); this->scene()->update();

View file

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

View file

@ -13,44 +13,23 @@ void DraggablePixmapItem::updatePosition() {
setX(x); setX(x);
setY(y); setY(y);
if (editor->selected_events && editor->selected_events->contains(this)) { if (editor->selected_events && editor->selected_events->contains(this)) {
setZValue(event->y() + 1); setZValue(event->getY() + 1);
} else { } else {
setZValue(event->y()); setZValue(event->getY());
} }
} }
void DraggablePixmapItem::emitPositionChanged() { void DraggablePixmapItem::emitPositionChanged() {
emit xChanged(event->x()); emit xChanged(event->getX());
emit yChanged(event->y()); emit yChanged(event->getY());
emit elevationChanged(event->elevation()); emit elevationChanged(event->getElevation());
} }
void DraggablePixmapItem::updatePixmap() { void DraggablePixmapItem::updatePixmap() {
editor->project->setEventPixmap(event, true); editor->project->setEventPixmap(event, true);
this->updatePosition(); this->updatePosition();
editor->redrawObject(this); editor->redrawObject(this);
emit spriteChanged(event->pixmap); emit spriteChanged(event->getPixmap());
}
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());
});
} }
void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) { void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) {
@ -63,8 +42,8 @@ void DraggablePixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *mouse) {
} }
void DraggablePixmapItem::move(int dx, int dy) { void DraggablePixmapItem::move(int dx, int dy) {
event->setX(event->x() + dx); event->setX(event->getX() + dx);
event->setY(event->y() + dy); event->setY(event->getY() + dy);
updatePosition(); updatePosition();
emitPositionChanged(); emitPositionChanged();
} }
@ -102,24 +81,27 @@ void DraggablePixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *) {
} }
void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) { void DraggablePixmapItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) {
QString eventType = this->event->get("event_type"); Event::Type eventType = this->event->getEventType();
if (eventType == EventType::Warp) { if (eventType == Event::Type::Warp) {
QString destMap = this->event->get("destination_map_name"); WarpEvent *warp = dynamic_cast<WarpEvent *>(this->event);
QString destMap = warp->getDestinationMap();
if (destMap != NONE_MAP_NAME) { 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) { else if (eventType == Event::Type::CloneObject) {
QString destMap = this->event->get("target_map"); CloneObjectEvent *clone = dynamic_cast<CloneObjectEvent *>(this->event);
QString destMap = clone->getTargetMap();
if (destMap != NONE_MAP_NAME) { 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) { else if (eventType == Event::Type::SecretBase) {
QString baseId = this->event->get("secret_base_id"); SecretBaseEvent *base = dynamic_cast<SecretBaseEvent *>(this->event);
QString baseId = base->getBaseID();
QString destMap = editor->project->mapConstantsToMapNames.value("MAP_" + baseId.left(baseId.lastIndexOf("_"))); QString destMap = editor->project->mapConstantsToMapNames.value("MAP_" + baseId.left(baseId.lastIndexOf("_")));
if (destMap != NONE_MAP_NAME) { 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; 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 // draw map border
// note: this will break when allowing map to be selected from drop down maybe // note: this will break when allowing map to be selected from drop down maybe
int borderHeight = 0, borderWidth = 0; int borderHeight = 0, borderWidth = 0;
@ -419,6 +404,21 @@ QPixmap MapImageExporter::getFormattedMapPixmap(Map *map, bool ignoreBorder) {
connectionPainter.end(); 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 // draw grid directly onto the pixmap
// since the last grid lines are outside of the pixmap, add a pixel to the bottom and right // since the last grid lines are outside of the pixmap, add a pixel to the bottom and right
if (showGrid) { if (showGrid) {

View file

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

View file

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

View file

@ -2,44 +2,45 @@
#include "scripting.h" #include "scripting.h"
#include "log.h" #include "log.h"
void OverlayText::render(QPainter *painter, int x, int y) { void OverlayText::render(QPainter *painter) {
QFont font = painter->font(); QFont font = painter->font();
font.setPixelSize(this->fontSize); font.setPixelSize(this->fontSize);
painter->setFont(font); painter->setFont(font);
painter->setPen(this->color); 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) { void OverlayPath::render(QPainter *painter) {
if (this->filled) { painter->fillPath(this->path, this->fillColor);
painter->fillRect(this->x + x, this->y + y, this->width, this->height, this->color); painter->setPen(this->borderColor);
} else { painter->drawPath(this->path);
painter->setPen(this->color);
painter->drawRect(this->x + x, this->y + y, this->width, this->height);
}
} }
void OverlayImage::render(QPainter *painter, int x, int y) { void OverlayImage::render(QPainter *painter) {
painter->drawImage(this->x + x, this->y + y, this->image); painter->drawImage(this->x, this->y, this->image);
} }
void Overlay::renderItems(QPainter *painter) { void Overlay::renderItems(QPainter *painter) {
if (this->hidden) return; 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) { if (this->clippingRect) {
painter->setClipping(true); painter->setClipping(true);
painter->setClipRect(*this->clippingRect); painter->setClipRect(*this->clippingRect);
} }
qreal oldOpacity = painter->opacity();
painter->setOpacity(this->opacity); painter->setOpacity(this->opacity);
for (auto item : this->items) for (auto item : this->items)
item->render(painter, this->x, this->y); item->render(painter);
painter->setOpacity(oldOpacity);
if (this->clippingRect) { painter->restore();
painter->setClipping(false);
}
} }
void Overlay::clearItems() { void Overlay::clearItems() {
@ -67,7 +68,7 @@ int Overlay::getOpacity() {
void Overlay::setOpacity(int opacity) { void Overlay::setOpacity(int opacity) {
if (opacity < 0 || opacity > 100) { 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; return;
} }
this->opacity = static_cast<qreal>(opacity) / 100; this->opacity = static_cast<qreal>(opacity) / 100;
@ -89,6 +90,44 @@ void Overlay::setY(int y) {
this->y = 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) { void Overlay::setClippingRect(QRectF rect) {
if (this->clippingRect) { if (this->clippingRect) {
delete this->clippingRect; delete this->clippingRect;
@ -113,12 +152,48 @@ void Overlay::move(int deltaX, int deltaY) {
this->y += deltaY; this->y += deltaY;
} }
void Overlay::addText(const QString text, int x, int y, QString color, int fontSize) { QColor Overlay::getColor(QString colorStr) {
this->items.append(new OverlayText(text, x, y, QColor(color), fontSize)); 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) { void Overlay::addText(const QString text, int x, int y, QString colorStr, int fontSize) {
this->items.append(new OverlayRect(x, y, width, height, QColor(color), filled)); 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) { 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) {