Merge pull request #192 from GriffinRichards/pokefirered

Add pokefirered support
This commit is contained in:
garak 2020-04-20 14:05:27 -04:00 committed by GitHub
commit 91f8db10a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 1438 additions and 583 deletions

View file

@ -7,15 +7,15 @@
<x>0</x>
<y>0</y>
<width>1117</width>
<height>747</height>
<height>788</height>
</rect>
</property>
<property name="windowTitle">
<string>porymap</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QGridLayout" name="gridLayout_15">
<item row="0" column="0">
<widget class="QSplitter" name="splitter_main">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -512,7 +512,7 @@
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<widget class="QPushButton" name="pushButton_ChangeDimensions">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Change a map layout's width and height.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
@ -561,8 +561,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>469</width>
<height>608</height>
<width>545</width>
<height>628</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_8">
@ -736,305 +736,6 @@
<property name="spacing">
<number>3</number>
</property>
<item row="0" column="0">
<widget class="QFrame" name="frame_Tilesets">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_PrimaryTileset">
<property name="text">
<string>Primary Tileset</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="NoScrollComboBox" name="comboBox_PrimaryTileset">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Primary Tileset&lt;/p&gt;&lt;p&gt;Defines the first 0x200 metatiles available for the map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_SecondaryTileset">
<property name="text">
<string>Secondary Tileset</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="NoScrollComboBox" name="comboBox_SecondaryTileset">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Secondary Tileset&lt;/p&gt;&lt;p&gt;Defines the second 0x200 metatiles available for the map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QFrame" name="frame_currentMetatileSelection">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>92</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>92</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Selection</string>
</property>
<layout class="QGridLayout" name="gridLayout_17">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QScrollArea" name="scrollArea_6">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_6">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>324</width>
<height>77</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_16">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGraphicsView" name="graphicsView_currentMetatileSelection">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="interactive">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_17">
<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>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Border</string>
</property>
<layout class="QGridLayout" name="gridLayout_16">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="1">
<widget class="QGraphicsView" name="graphicsView_BorderMetatile">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>48</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The border is a 2x2 metatile which is repeated outside of the map layout's boundary. Draw on this border area to modify it.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_13">
<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>
</widget>
</item>
<item row="3" column="0">
<widget class="QScrollArea" name="scrollArea_2">
<property name="sizePolicy">
@ -1064,10 +765,10 @@
</property>
<property name="geometry">
<rect>
<x>0</x>
<x>8</x>
<y>0</y>
<width>307</width>
<height>362</height>
<width>221</width>
<height>324</height>
</rect>
</property>
<property name="sizePolicy">
@ -1160,6 +861,309 @@
</widget>
</widget>
</item>
<item row="2" column="0">
<widget class="QFrame" name="frame_currentMetatileSelection">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>92</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>92</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Selection</string>
</property>
<layout class="QGridLayout" name="gridLayout_17">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QScrollArea" name="scrollArea_6">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_6">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>256</width>
<height>74</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_16">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGraphicsView" name="graphicsView_currentMetatileSelection">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="interactive">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_17">
<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>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>110</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>110</height>
</size>
</property>
<property name="title">
<string>Border</string>
</property>
<layout class="QGridLayout" name="gridLayout_16">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinAndMaxSize</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QScrollArea" name="scrollArea_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>231</width>
<height>83</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_18">
<item row="0" column="0">
<widget class="QGraphicsView" name="graphicsView_BorderMetatile">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>1</width>
<height>1</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The border is a group of metatiles which are repeated outside of the map layout's boundary. Draw on this border area to modify it.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0">
<widget class="QSlider" name="horizontalSlider_MetatileZoom">
<property name="minimum">
@ -1176,6 +1180,64 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QFrame" name="frame_Tilesets">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_PrimaryTileset">
<property name="text">
<string>Primary Tileset</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="NoScrollComboBox" name="comboBox_PrimaryTileset">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Primary Tileset&lt;/p&gt;&lt;p&gt;Defines the first 0x200 metatiles available for the map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_SecondaryTileset">
<property name="text">
<string>Secondary Tileset</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="NoScrollComboBox" name="comboBox_SecondaryTileset">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Secondary Tileset&lt;/p&gt;&lt;p&gt;Defines the second 0x200 metatiles available for the map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_collision">
@ -1344,8 +1406,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>657</height>
<width>371</width>
<height>684</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_7">
@ -1618,7 +1680,7 @@
<x>0</x>
<y>0</y>
<width>430</width>
<height>568</height>
<height>575</height>
</rect>
</property>
<property name="sizePolicy">
@ -2094,6 +2156,26 @@
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_FloorNumber">
<property name="text">
<string>Floor Number</string>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QSpinBox" name="spinBox_FloorNumber">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Floor number to be used for maps with elevators.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>-128</number>
</property>
<property name="maximum">
<number>127</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -2531,8 +2613,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>826</width>
<height>557</height>
<width>818</width>
<height>574</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_14">
@ -2796,7 +2878,7 @@
<x>0</x>
<y>0</y>
<width>1117</width>
<height>21</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">

View file

@ -73,7 +73,7 @@
<item row="2" column="0">
<widget class="QLabel" name="label_NewMap_Width">
<property name="text">
<string>Width</string>
<string>Map Width</string>
</property>
</widget>
</item>
@ -90,7 +90,7 @@
<item row="3" column="0">
<widget class="QLabel" name="label_NewMap_Height">
<property name="text">
<string>Height</string>
<string>Map Height</string>
</property>
</widget>
</item>
@ -105,13 +105,47 @@
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_NewMap_BorderWidth">
<property name="text">
<string>Border Width</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinBox_NewMap_BorderWidth">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width (in blocks) of the new map's border.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_NewMap_BorderHeight">
<property name="text">
<string>Border Height</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="spinBox_NewMap_BorderHeight">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height (in blocks) of the new map's border.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_NewMap_Primary_Tileset">
<property name="text">
<string>Primary Tileset</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="6" column="1">
<widget class="NoScrollComboBox" name="comboBox_NewMap_Primary_Tileset">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The primary tileset for the new map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -121,14 +155,14 @@
</property>
</widget>
</item>
<item row="5" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_NewMap_Secondary_Tileset">
<property name="text">
<string>Secondary Tileset</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="7" column="1">
<widget class="NoScrollComboBox" name="comboBox_NewMap_Secondary_Tileset">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The secondary tileset for the new map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -138,14 +172,14 @@
</property>
</widget>
</item>
<item row="6" column="0">
<item row="8" column="0">
<widget class="QLabel" name="label_NewMap_Type">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="8" column="1">
<widget class="NoScrollComboBox" name="comboBox_NewMap_Type">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The map type is a general attribute, which is used for many different things. For example. it determines whether biking or running is allowed.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -155,14 +189,14 @@
</property>
</widget>
</item>
<item row="7" column="0">
<item row="9" column="0">
<widget class="QLabel" name="label_NewMap_Location">
<property name="text">
<string>Location</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="9" column="1">
<widget class="NoScrollComboBox" name="comboBox_NewMap_Location">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The section of the region map which the map is grouped under. This also determines the name of the map that is displayed when the player enters it.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -172,14 +206,14 @@
</property>
</widget>
</item>
<item row="8" column="0">
<item row="10" column="0">
<widget class="QLabel" name="label_NewMap_Flyable">
<property name="text">
<string>Can Fly To</string>
</property>
</widget>
</item>
<item row="8" column="1">
<item row="10" column="1">
<widget class="QCheckBox" name="checkBox_NewMap_Flyable">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Whether to add a heal location to the new map.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -189,48 +223,65 @@
</property>
</widget>
</item>
<item row="9" column="0">
<item row="11" column="0">
<widget class="QLabel" name="label_NewMap_Allow_Running">
<property name="text">
<string>Allow Running</string>
</property>
</widget>
</item>
<item row="10" column="0">
<item row="12" column="0">
<widget class="QLabel" name="label_NewMap_Allow_Biking">
<property name="text">
<string>Allow Biking</string>
</property>
</widget>
</item>
<item row="11" column="0">
<item row="13" column="0">
<widget class="QLabel" name="label_NewMap_Allow_Escape_Rope">
<property name="text">
<string>Allow Escape Rope</string>
</property>
</widget>
</item>
<item row="9" column="1">
<item row="11" column="1">
<widget class="QCheckBox" name="checkBox_NewMap_Allow_Running">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="10" column="1">
<item row="12" column="1">
<widget class="QCheckBox" name="checkBox_NewMap_Allow_Biking">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="11" column="1">
<item row="13" column="1">
<widget class="QCheckBox" name="checkBox_NewMap_Allow_Escape_Rope">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="14" column="0">
<widget class="QLabel" name="label_NewMap_Floor_Number">
<property name="text">
<string>Floor Number</string>
</property>
</widget>
</item>
<item row="14" column="1">
<widget class="QSpinBox" name="spinBox_NewMap_Floor_Number">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Floor number to be used for maps with elevators.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>127</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View file

@ -47,7 +47,7 @@
<x>0</x>
<y>0</y>
<width>272</width>
<height>539</height>
<height>625</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
@ -198,30 +198,31 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="4" column="0" colspan="3">
<widget class="QLabel" name="label_8">
<item row="13" column="0" colspan="3">
<widget class="QLabel" name="label_metatileLabel">
<property name="text">
<string>Metatile Label (Optional)</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="3">
<widget class="QLineEdit" name="lineEdit_metatileLabel"/>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="label_5">
<item row="0" column="2">
<widget class="QLabel" name="label_layerType">
<property name="text">
<string>Metatile Behavior</string>
<string>Layer Type</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="NoScrollComboBox" name="comboBox_metatileBehaviors"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<item row="9" column="0">
<widget class="QLabel" name="label_encounterType">
<property name="text">
<string>Bottom/Top</string>
<string>Encounter Type</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_terrainType">
<property name="text">
<string>Terrain Type</string>
</property>
</widget>
</item>
@ -247,15 +248,15 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_6">
<item row="0" column="0">
<widget class="QLabel" name="label_BottomTop">
<property name="text">
<string>Layer Type</string>
<string>Bottom/Top</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="comboBox_layerType"/>
<item row="10" column="0">
<widget class="QComboBox" name="comboBox_encounterType"/>
</item>
<item row="1" column="1">
<spacer name="horizontalSpacer_5">
@ -270,6 +271,38 @@
</property>
</spacer>
</item>
<item row="14" column="0" colspan="3">
<widget class="QLineEdit" name="lineEdit_metatileLabel"/>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="comboBox_layerType"/>
</item>
<item row="8" column="0" colspan="3">
<widget class="NoScrollComboBox" name="comboBox_metatileBehaviors" native="true"/>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label_metatileBehavior">
<property name="text">
<string>Metatile Behavior</string>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QComboBox" name="comboBox_terrainType"/>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@ -377,8 +410,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>367</height>
<width>384</width>
<height>265</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
@ -394,19 +427,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="2">
<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>
<item row="0" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
@ -420,16 +440,6 @@
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QGraphicsView" name="graphicsView_Tiles">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
@ -443,6 +453,29 @@
</property>
</spacer>
</item>
<item row="1" column="2">
<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>
<item row="1" column="1">
<widget class="QGraphicsView" name="graphicsView_Tiles">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer_3">
<property name="orientation">
@ -471,7 +504,7 @@
<x>0</x>
<y>0</y>
<width>700</width>
<height>21</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -572,6 +605,13 @@
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>NoScrollComboBox</class>
<extends>QWidget</extends>
<header>noscrollcombobox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View file

@ -109,6 +109,8 @@ public:
void setUsePoryScript(bool usePoryScript);
bool getUsePoryScript();
void setProjectDir(QString projectDir);
void setUseCustomBorderSize(bool enable);
bool getUseCustomBorderSize();
protected:
QString getConfigFilepath();
void parseConfigKeyValue(QString key, QString value);
@ -119,6 +121,7 @@ private:
QString projectDir;
bool useEncounterJson;
bool usePoryScript;
bool useCustomBorderSize;
};
extern ProjectConfig projectConfig;

View file

@ -9,14 +9,17 @@ class HealLocation {
public:
HealLocation()=default;
HealLocation(QString, int, uint16_t, uint16_t);
HealLocation(QString, QString, int, uint16_t, uint16_t, QString = "", uint16_t = 0);
friend QDebug operator<<(QDebug debug, const HealLocation &hl);
public:
QString name;
QString idName;
QString mapName;
int index;
uint16_t x;
uint16_t y;
QString respawnMap;
uint16_t respawnNPC;
static HealLocation fromEvent(Event*);
};

View file

@ -6,9 +6,12 @@
class HistoryItem {
public:
Blockdata *metatiles;
Blockdata *border;
int layoutWidth;
int layoutHeight;
HistoryItem(Blockdata *metatiles, int layoutWidth, int layoutHeight);
int borderWidth;
int borderHeight;
HistoryItem(Blockdata *metatiles, Blockdata *border, int layoutWidth, int layoutHeight, int borderWidth, int borderHeight);
~HistoryItem();
};

View file

@ -14,6 +14,13 @@
#include <QGraphicsPixmapItem>
#include <math.h>
#define DEFAULT_BORDER_WIDTH 2
#define DEFAULT_BORDER_HEIGHT 2
// Number of metatiles to draw out from edge of map. Could allow modification of this in the future.
// porymap will reflect changes to it, but the value is hard-coded in the projects at the moment
#define BORDER_DISTANCE 7
class Map : public QObject
{
Q_OBJECT
@ -35,6 +42,7 @@ public:
QString allowRunning;
QString allowBiking;
QString allowEscapeRope;
int floorNumber;
QString battle_scene;
QString sharedEventsMap = "";
QString sharedScriptsMap = "";
@ -57,6 +65,8 @@ public:
static QString bgEventsLabelFromName(QString mapName);
int getWidth();
int getHeight();
int getBorderWidth();
int getBorderHeight();
QPixmap render(bool ignoreCache, MapLayout * fromLayout = nullptr);
QPixmap renderCollision(qreal opacity, bool ignoreCache);
bool mapBlockChanged(int i, Blockdata * cache);
@ -77,12 +87,14 @@ public:
void addEvent(Event*);
QPixmap renderConnection(MapConnection, MapLayout *);
QPixmap renderBorder();
void setDimensions(int newWidth, int newHeight, bool setNewBlockData = true);
void setDimensions(int newWidth, int newHeight, bool setNewBlockdata = true);
void setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata = true);
void cacheBorder();
bool hasUnsavedChanges();
private:
void setNewDimensionsBlockdata(int newWidth, int newHeight);
void setNewBorderDimensionsBlockdata(int newWidth, int newHeight);
signals:
void mapChanged(Map *map);

View file

@ -15,6 +15,8 @@ public:
QString name;
QString width;
QString height;
QString border_width;
QString border_height;
QString border_path;
QString blockdata_path;
QString tileset_primary_label;

View file

@ -11,8 +11,10 @@ public:
Metatile();
public:
QList<Tile> *tiles = nullptr;
uint8_t behavior;
uint16_t behavior; // 8 bits RSE, 9 bits FRLG
uint8_t layerType;
uint8_t encounterType; // FRLG only
uint8_t terrainType; // FRLG only
QString label;
Metatile *copy();

View file

@ -147,6 +147,7 @@ private:
void updateMirroredConnectionMap(MapConnection*, QString);
void updateMirroredConnection(MapConnection*, QString, QString, bool isDelete = false);
void updateEncounterFields(EncounterFields newFields);
int getBorderDrawDistance(int dimension);
Event* createNewObjectEvent();
Event* createNewWarpEvent();
Event* createNewHealLocationEvent();

View file

@ -68,6 +68,7 @@ private slots:
void on_checkBox_AllowRunning_clicked(bool checked);
void on_checkBox_AllowBiking_clicked(bool checked);
void on_checkBox_AllowEscapeRope_clicked(bool checked);
void on_spinBox_FloorNumber_valueChanged(int offset);
void on_tabWidget_currentChanged(int index);
@ -118,7 +119,7 @@ private slots:
void on_comboBox_EmergeMap_currentTextChanged(const QString &mapName);
void on_comboBox_PrimaryTileset_currentTextChanged(const QString &arg1);
void on_comboBox_SecondaryTileset_currentTextChanged(const QString &arg1);
void on_pushButton_clicked();
void on_pushButton_ChangeDimensions_clicked();
void on_checkBox_smartPaths_stateChanged(int selected);
void on_checkBox_Visibility_clicked(bool checked);
void on_checkBox_ToggleBorder_stateChanged(int arg1);
@ -215,6 +216,7 @@ private:
bool openRecentProject();
void updateTilesetEditor();
QString getEventGroupFromTabWidget(QWidget *tab);
void closeSupplementaryWindows();
bool isProjectOpen();
};

View file

@ -50,6 +50,7 @@ public:
QStringList *coordEventWeatherNames = nullptr;
QStringList *secretBaseIds = nullptr;
QStringList *bgEventFacingDirections = nullptr;
QStringList *trainerTypes = nullptr;
QMap<QString, int> metatileBehaviorMap;
QMap<int, QString> metatileBehaviorMapInverse;
QMap<QString, QString> facingDirections;
@ -127,6 +128,7 @@ public:
void saveTilesetTilesImage(Tileset*);
void saveTilesetPalettes(Tileset*, bool);
QString defaultSong;
QStringList getSongNames();
QStringList getVisibilities();
QMap<QString, QStringList> getTilesetLabels();
@ -143,6 +145,7 @@ public:
bool readCoordEventWeatherNames();
bool readSecretBaseIds();
bool readBgEventFacingDirections();
bool readTrainerTypes();
bool readMetatileBehaviors();
bool readHealLocations();
bool readMiscellaneousConstants();

View file

@ -10,6 +10,14 @@ class NewEventToolButton : public QToolButton
public:
explicit NewEventToolButton(QWidget *parent = nullptr);
QString getSelectedEventType();
QAction *newObjectAction;
QAction *newWarpAction;
QAction *newHealLocationAction;
QAction *newTriggerAction;
QAction *newWeatherTriggerAction;
QAction *newSignAction;
QAction *newHiddenItemAction;
QAction *newSecretBaseAction;
public slots:
void newObject();
void newWarp();
@ -23,14 +31,6 @@ signals:
void newEventAdded(QString);
private:
QString selectedEventType;
QAction *newObjectAction;
QAction *newWarpAction;
QAction *newHealLocationAction;
QAction *newTriggerAction;
QAction *newWeatherTriggerAction;
QAction *newSignAction;
QAction *newHiddenItemAction;
QAction *newSecretBaseAction;
void init();
};

View file

@ -77,6 +77,10 @@ private slots:
void on_comboBox_layerType_activated(int arg1);
void on_comboBox_encounterType_activated(int arg1);
void on_comboBox_terrainType_activated(int arg1);
void on_actionExport_Primary_Tiles_Image_triggered();
void on_actionExport_Secondary_Tiles_Image_triggered();

View file

@ -324,11 +324,13 @@ QString PorymapConfig::getTheme() {
const QMap<BaseGameVersion, QString> baseGameVersionMap = {
{BaseGameVersion::pokeruby, "pokeruby"},
{BaseGameVersion::pokefirered, "pokefirered"},
{BaseGameVersion::pokeemerald, "pokeemerald"},
};
const QMap<QString, BaseGameVersion> baseGameVersionReverseMap = {
{"pokeruby", BaseGameVersion::pokeruby},
{"pokefirered", BaseGameVersion::pokefirered},
{"pokeemerald", BaseGameVersion::pokeemerald},
};
@ -346,7 +348,7 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
this->baseGameVersion = baseGameVersionReverseMap.value(baseGameVersion);
} else {
this->baseGameVersion = BaseGameVersion::pokeemerald;
logWarn(QString("Invalid config value for base_game_version: '%1'. Must be 'pokeruby' or 'pokeemerald'.").arg(value));
logWarn(QString("Invalid config value for base_game_version: '%1'. Must be 'pokeruby', 'pokefirered' or 'pokeemerald'.").arg(value));
}
} else if (key == "use_encounter_json") {
bool ok;
@ -354,12 +356,18 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
if (!ok) {
logWarn(QString("Invalid config value for use_encounter_json: '%1'. Must be 0 or 1.").arg(value));
}
} else if(key == "use_poryscript") {
} else if (key == "use_poryscript") {
bool ok;
this->usePoryScript = value.toInt(&ok);
if(!ok) {
if (!ok) {
logWarn(QString("Invalid config value for use_poryscript: '%1'. Must be 0 or 1.").arg(value));
}
} else if (key == "use_custom_border_size") {
bool ok;
this->useCustomBorderSize = value.toInt(&ok);
if (!ok) {
logWarn(QString("Invalid config value for use_custom_border_size: '%1'. Must be 0 or 1.").arg(value));
}
} else {
logWarn(QString("Invalid config key found in config file %1: '%2'").arg(this->getConfigFilepath()).arg(key));
}
@ -370,6 +378,7 @@ QMap<QString, QString> ProjectConfig::getKeyValueMap() {
map.insert("base_game_version", baseGameVersionMap.value(this->baseGameVersion));
map.insert("use_encounter_json", QString::number(this->useEncounterJson));
map.insert("use_poryscript", QString::number(this->usePoryScript));
map.insert("use_custom_border_size", QString::number(this->useCustomBorderSize));
return map;
}
@ -387,6 +396,7 @@ void ProjectConfig::onNewConfigFileCreated() {
QComboBox *baseGameVersionComboBox = new QComboBox();
baseGameVersionComboBox->addItem("pokeruby", BaseGameVersion::pokeruby);
baseGameVersionComboBox->addItem("pokefirered", BaseGameVersion::pokefirered);
baseGameVersionComboBox->addItem("pokeemerald", BaseGameVersion::pokeemerald);
form.addRow(new QLabel("Game Version"), baseGameVersionComboBox);
@ -398,6 +408,7 @@ void ProjectConfig::onNewConfigFileCreated() {
this->baseGameVersion = static_cast<BaseGameVersion>(baseGameVersionComboBox->currentData().toInt());
}
}
this->useCustomBorderSize = this->baseGameVersion == BaseGameVersion::pokefirered;
this->useEncounterJson = true;
this->usePoryScript = false;
}
@ -432,3 +443,12 @@ void ProjectConfig::setUsePoryScript(bool usePoryScript) {
bool ProjectConfig::getUsePoryScript() {
return this->usePoryScript;
}
void ProjectConfig::setUseCustomBorderSize(bool enable) {
this->useCustomBorderSize = enable;
this->save();
}
bool ProjectConfig::getUseCustomBorderSize() {
return this->useCustomBorderSize;
}

View file

@ -1,6 +1,7 @@
#include "event.h"
#include "map.h"
#include "project.h"
#include "config.h"
QString EventType::Object = "event_object";
QString EventType::Warp = "event_warp";
@ -58,6 +59,9 @@ Event* Event::createNewObjectEvent(Project *project)
event->put("event_type", EventType::Object);
event->put("sprite", project->getEventObjGfxConstants().keys().first());
event->put("movement_type", project->movementTypes->first());
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
event->put("in_connection", false);
}
event->put("radius_x", 0);
event->put("radius_y", 0);
event->put("script_label", "NULL");
@ -86,7 +90,12 @@ Event* Event::createNewHealLocationEvent(QString map_name)
event->put("event_group_type", "heal_event_group");
event->put("event_type", EventType::HealLocation);
event->put("loc_name", QString(Map::mapConstantFromName(map_name)).remove(0,4));
event->put("id_name", map_name.replace(QRegularExpression("([a-z])([A-Z])"), "\\1_\\2").toUpper());
event->put("elevation", 3);
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
event->put("respawn_map", map_name);
event->put("respawn_npc", 1);
}
return event;
}
@ -131,6 +140,10 @@ Event* Event::createNewHiddenItemEvent(Project *project)
event->put("item", project->itemNames->first());
event->put("flag", project->flagNames->first());
event->put("elevation", 3);
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
event->put("quantity", 1);
event->put("underfoot", false);
}
return event;
}
@ -158,19 +171,36 @@ QMap<QString, bool> Event::getExpectedFields()
{
QString type = this->get("event_type");
if (type == EventType::Object) {
return QMap<QString, bool> {
{"graphics_id", true},
{"x", true},
{"y", true},
{"elevation", true},
{"movement_type", true},
{"movement_range_x", true},
{"movement_range_y", true},
{"trainer_type", true},
{"trainer_sight_or_berry_tree_id", true},
{"script", true},
{"flag", true},
};
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
return QMap<QString, bool> {
{"graphics_id", true},
{"in_connection", true},
{"x", true},
{"y", true},
{"elevation", true},
{"movement_type", true},
{"movement_range_x", true},
{"movement_range_y", true},
{"trainer_type", true},
{"trainer_sight_or_berry_tree_id", true},
{"script", true},
{"flag", true},
};
} else {
return QMap<QString, bool> {
{"graphics_id", true},
{"x", true},
{"y", true},
{"elevation", true},
{"movement_type", true},
{"movement_range_x", true},
{"movement_range_y", true},
{"trainer_type", true},
{"trainer_sight_or_berry_tree_id", true},
{"script", true},
{"flag", true},
};
}
} else if (type == EventType::Warp) {
return QMap<QString, bool> {
{"x", true},
@ -207,14 +237,27 @@ QMap<QString, bool> Event::getExpectedFields()
{"script", true},
};
} else if (type == EventType::HiddenItem) {
return QMap<QString, bool> {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"item", true},
{"flag", true},
};
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
return QMap<QString, bool> {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"item", true},
{"flag", true},
{"quantity", true},
{"underfoot", true},
};
} else {
return QMap<QString, bool> {
{"type", true},
{"x", true},
{"y", true},
{"elevation", true},
{"item", true},
{"flag", true},
};
}
} else if (type == EventType::SecretBase) {
return QMap<QString, bool> {
{"type", true},
@ -252,6 +295,9 @@ OrderedJson::object Event::buildObjectEventJSON()
{
OrderedJson::object eventObj;
eventObj["graphics_id"] = this->get("sprite");
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
eventObj["in_connection"] = this->getInt("in_connection") > 0 || this->get("in_connection") == "TRUE";
}
eventObj["x"] = this->getU16("x");
eventObj["y"] = this->getU16("y");
eventObj["elevation"] = this->getInt("elevation");
@ -331,6 +377,10 @@ OrderedJson::object Event::buildHiddenItemEventJSON()
hiddenItemObj["elevation"] = this->getInt("elevation");
hiddenItemObj["item"] = this->get("item");
hiddenItemObj["flag"] = this->get("flag");
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
hiddenItemObj["quantity"] = this->getInt("quantity");
hiddenItemObj["underfoot"] = this->getInt("underfoot") > 0 || this->get("underfoot") == "TRUE";
}
this->addCustomValuesTo(&hiddenItemObj);
return hiddenItemObj;

View file

@ -1,17 +1,23 @@
#include "heallocation.h"
#include "config.h"
#include "map.h"
HealLocation::HealLocation(QString map, int i, uint16_t x, uint16_t y)
HealLocation::HealLocation(QString id, QString map, int i, uint16_t x, uint16_t y, QString respawnMap, uint16_t respawnNPC)
{
this->name = map;
this->idName = id;
this->mapName = map;
this->index = i;
this->x = x;
this->y = y;
this->respawnMap = respawnMap;
this->respawnNPC = respawnNPC;
}
HealLocation HealLocation::fromEvent(Event *event)
{
HealLocation hl;
hl.name = event->get("loc_name");
hl.idName = event->get("id_name");
hl.mapName = event->get("loc_name");
try {
hl.index = event->get("index").toInt();
}
@ -20,11 +26,15 @@ HealLocation HealLocation::fromEvent(Event *event)
}
hl.x = event->getU16("x");
hl.y = event->getU16("y");
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
hl.respawnNPC = event->getU16("respawn_npc");
hl.respawnMap = Map::mapConstantFromName(event->get("respawn_map")).remove(0,4);
}
return hl;
}
QDebug operator<<(QDebug debug, const HealLocation &hl)
{
debug << "HealLocation_" + hl.name << "(" << hl.x << ',' << hl.y << ")";
debug << "HealLocation_" + hl.mapName << "(" << hl.x << ',' << hl.y << ")";
return debug;
}

View file

@ -1,13 +1,17 @@
#include "historyitem.h"
HistoryItem::HistoryItem(Blockdata *metatiles, int layoutWidth, int layoutHeight) {
HistoryItem::HistoryItem(Blockdata *metatiles, Blockdata *border, int layoutWidth, int layoutHeight, int borderWidth, int borderHeight) {
this->metatiles = metatiles;
this->border = border;
this->layoutWidth = layoutWidth;
this->layoutHeight = layoutHeight;
this->borderWidth = borderWidth;
this->borderHeight = borderHeight;
}
HistoryItem::~HistoryItem() {
if (this->metatiles) delete this->metatiles;
if (this->border) delete this->border;
}
RegionMapHistoryItem::RegionMapHistoryItem(int which, QVector<uint8_t> tiles, QString cityMap) {

View file

@ -59,6 +59,14 @@ int Map::getHeight() {
return layout->height.toInt(nullptr, 0);
}
int Map::getBorderWidth() {
return layout->border_width.toInt(nullptr, 0);
}
int Map::getBorderHeight() {
return layout->border_height.toInt(nullptr, 0);
}
bool Map::mapBlockChanged(int i, Blockdata * cache) {
if (!cache)
return true;
@ -213,27 +221,33 @@ QPixmap Map::render(bool ignoreCache = false, MapLayout * fromLayout) {
}
QPixmap Map::renderBorder() {
bool changed_any = false;
int width_ = 2;
int height_ = 2;
bool changed_any = false, border_resized = false;
int width_ = getBorderWidth();
int height_ = getBorderHeight();
if (layout->border_image.isNull()) {
layout->border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
changed_any = true;
}
if (layout->border_image.width() != width_ * 16 || layout->border_image.height() != height_ * 16) {
layout->border_image = QImage(width_ * 16, height_ * 16, QImage::Format_RGBA8888);
border_resized = true;
}
if (!(layout->border && layout->border->blocks)) {
layout->border_pixmap = layout->border_pixmap.fromImage(layout->border_image);
return layout->border_pixmap;
}
QPainter painter(&layout->border_image);
for (int i = 0; i < layout->border->blocks->length(); i++) {
if (!borderBlockChanged(i, layout->cached_border)) {
if (!border_resized && !borderBlockChanged(i, layout->cached_border)) {
continue;
}
changed_any = true;
Block block = layout->border->blocks->value(i);
QImage metatile_image = getMetatileImage(block.tile, layout->tileset_primary, layout->tileset_secondary);
int map_y = i / width_;
int map_x = i % width_;
uint16_t tile = block.tile;
QImage metatile_image = getMetatileImage(tile, layout->tileset_primary, layout->tileset_secondary);
int map_y = width_ ? i / width_ : 0;
int map_x = width_ ? i % width_ : 0;
painter.drawImage(QPoint(map_x * 16, map_y * 16), metatile_image);
}
painter.end();
@ -249,23 +263,23 @@ QPixmap Map::renderConnection(MapConnection connection, MapLayout * fromLayout)
int x, y, w, h;
if (connection.direction == "up") {
x = 0;
y = getHeight() - 6;
y = getHeight() - BORDER_DISTANCE;
w = getWidth();
h = 6;
h = BORDER_DISTANCE;
} else if (connection.direction == "down") {
x = 0;
y = 0;
w = getWidth();
h = 6;
h = BORDER_DISTANCE;
} else if (connection.direction == "left") {
x = getWidth() - 6;
x = getWidth() - BORDER_DISTANCE;
y = 0;
w = 6;
w = BORDER_DISTANCE;
h = getHeight();
} else if (connection.direction == "right") {
x = 0;
y = 0;
w = 6;
w = BORDER_DISTANCE;
h = getHeight();
} else {
// this should not happen
@ -298,6 +312,25 @@ void Map::setNewDimensionsBlockdata(int newWidth, int newHeight) {
layout->blockdata->copyFrom(newBlockData);
}
void Map::setNewBorderDimensionsBlockdata(int newWidth, int newHeight) {
int oldWidth = getBorderWidth();
int oldHeight = getBorderHeight();
Blockdata* newBlockData = new Blockdata;
for (int y = 0; y < newHeight; y++)
for (int x = 0; x < newWidth; x++) {
if (x < oldWidth && y < oldHeight) {
int index = y * oldWidth + x;
newBlockData->addBlock(layout->border->blocks->value(index));
} else {
newBlockData->addBlock(0);
}
}
layout->border->copyFrom(newBlockData);
}
void Map::setDimensions(int newWidth, int newHeight, bool setNewBlockdata) {
if (setNewBlockdata) {
setNewDimensionsBlockdata(newWidth, newHeight);
@ -309,6 +342,17 @@ void Map::setDimensions(int newWidth, int newHeight, bool setNewBlockdata) {
emit mapChanged(this);
}
void Map::setBorderDimensions(int newWidth, int newHeight, bool setNewBlockdata) {
if (setNewBlockdata) {
setNewBorderDimensionsBlockdata(newWidth, newHeight);
}
layout->border_width = QString::number(newWidth);
layout->border_height = QString::number(newHeight);
emit mapChanged(this);
}
Block* Map::getBlock(int x, int y) {
if (layout->blockdata && layout->blockdata->blocks) {
if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
@ -363,35 +407,63 @@ void Map::_floodFillCollisionElevation(int x, int y, uint16_t collision, uint16_
}
void Map::undo() {
bool redraw = false, changed = false;
HistoryItem *commit = metatileHistory.back();
if (!commit)
return;
if (layout->blockdata) {
layout->blockdata->copyFrom(commit->metatiles);
if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight())
{
if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight()) {
this->setDimensions(commit->layoutWidth, commit->layoutHeight, false);
emit mapNeedsRedrawing();
redraw = true;
}
changed = true;
}
if (layout->border) {
layout->border->copyFrom(commit->border);
if (commit->borderWidth != this->getBorderWidth() || commit->borderHeight != this->getBorderHeight()) {
this->setBorderDimensions(commit->borderWidth, commit->borderHeight, false);
redraw = true;
}
changed = true;
}
if (redraw) {
emit mapNeedsRedrawing();
}
if (changed) {
emit mapChanged(this);
}
}
void Map::redo() {
bool redraw = false, changed = false;
HistoryItem *commit = metatileHistory.next();
if (!commit)
return;
if (layout->blockdata) {
layout->blockdata->copyFrom(commit->metatiles);
if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight())
{
if (commit->layoutWidth != this->getWidth() || commit->layoutHeight != this->getHeight()) {
this->setDimensions(commit->layoutWidth, commit->layoutHeight, false);
emit mapNeedsRedrawing();
redraw = true;
}
changed = true;
}
if (layout->border) {
layout->border->copyFrom(commit->border);
if (commit->borderWidth != this->getBorderWidth() || commit->borderHeight != this->getBorderHeight()) {
this->setBorderDimensions(commit->borderWidth, commit->borderHeight, false);
redraw = true;
}
changed = true;
}
if (redraw) {
emit mapNeedsRedrawing();
}
if (changed) {
emit mapChanged(this);
}
}
@ -401,14 +473,22 @@ void Map::commit() {
return;
}
int layoutWidth = this->getWidth();
int layoutHeight = this->getHeight();
int borderWidth = this->getBorderWidth();
int borderHeight = this->getBorderHeight();
if (layout->blockdata) {
HistoryItem *item = metatileHistory.current();
bool atCurrentHistory = item
&& layout->blockdata->equals(item->metatiles)
&& this->getWidth() == item->layoutWidth
&& this->getHeight() == item->layoutHeight;
&& layout->border->equals(item->border)
&& layoutWidth == item->layoutWidth
&& layoutHeight == item->layoutHeight
&& borderWidth == item->borderWidth
&& borderHeight == item->borderHeight;
if (!atCurrentHistory) {
HistoryItem *commit = new HistoryItem(layout->blockdata->copy(), this->getWidth(), this->getHeight());
HistoryItem *commit = new HistoryItem(layout->blockdata->copy(), layout->border->copy(), layoutWidth, layoutHeight, borderWidth, borderHeight);
metatileHistory.push(commit);
emit mapChanged(this);
}

View file

@ -11,6 +11,8 @@ Metatile* Metatile::copy() {
Metatile *copy = new Metatile;
copy->behavior = this->behavior;
copy->layerType = this->layerType;
copy->encounterType = this->encounterType;
copy->terrainType = this->terrainType;
copy->tiles = new QList<Tile>;
copy->label = this->label;
for (Tile tile : *this->tiles) {
@ -22,6 +24,8 @@ Metatile* Metatile::copy() {
void Metatile::copyInPlace(Metatile *other) {
this->behavior = other->behavior;
this->layerType = other->layerType;
this->encounterType = other->encounterType;
this->terrainType = other->terrainType;
this->label = other->label;
for (int i = 0; i < this->tiles->length(); i++) {
(*this->tiles)[i] = other->tiles->at(i);

View file

@ -84,6 +84,8 @@ QList<Metatile*> *MetatileParser::parse(QString filepath, bool *error, bool prim
(static_cast<unsigned char>(in.at(attrOffset + 1)) << 8);
metatile->behavior = value & 0xFF;
metatile->layerType = (value & 0xF000) >> 12;
metatile->encounterType = 0;
metatile->terrainType = 0;
metatile->tiles = tiles;
metatiles->append(metatile);
}

View file

@ -2,6 +2,7 @@
#include "metatile.h"
#include "project.h"
#include "log.h"
#include "config.h"
#include <QPainter>
#include <QImage>
@ -115,8 +116,13 @@ bool Tileset::appendToHeaders(QString headerFile, QString friendlyName){
dataString.append(QString("\t.4byte gTilesetTiles_%1\n").arg(friendlyName));
dataString.append(QString("\t.4byte gTilesetPalettes_%1\n").arg(friendlyName));
dataString.append(QString("\t.4byte gMetatiles_%1\n").arg(friendlyName));
dataString.append(QString("\t.4byte gMetatileAttributes_%1\n").arg(friendlyName));
dataString.append("\t.4byte NULL\n");
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
dataString.append("\t.4byte NULL\n");
dataString.append(QString("\t.4byte gMetatileAttributes_%1\n").arg(friendlyName));
} else {
dataString.append(QString("\t.4byte gMetatileAttributes_%1\n").arg(friendlyName));
dataString.append("\t.4byte NULL\n");
}
file.write(dataString.toUtf8());
file.flush();
file.close();

View file

@ -48,6 +48,8 @@ void Editor::undo() {
map->undo();
map_item->draw();
collision_item->draw();
selected_border_metatiles_item->draw();
displayMapBorder();
}
}
@ -56,6 +58,8 @@ void Editor::redo() {
map->redo();
map_item->draw();
collision_item->draw();
selected_border_metatiles_item->draw();
displayMapBorder();
}
}
@ -1136,10 +1140,10 @@ void Editor::displayMapMetatiles() {
int tw = 16;
int th = 16;
scene->setSceneRect(
-6 * tw,
-6 * th,
map_item->pixmap().width() + 12 * tw,
map_item->pixmap().height() + 12 * th
-BORDER_DISTANCE * tw,
-BORDER_DISTANCE * th,
map_item->pixmap().width() + BORDER_DISTANCE * 2 * tw,
map_item->pixmap().height() + BORDER_DISTANCE * 2 * th
);
}
@ -1334,9 +1338,13 @@ void Editor::displayMapBorder() {
}
borderItems.clear();
int borderWidth = map->getBorderWidth();
int borderHeight = map->getBorderHeight();
int borderHorzDist = getBorderDrawDistance(borderWidth);
int borderVertDist = getBorderDrawDistance(borderHeight);
QPixmap pixmap = map->renderBorder();
for (int y = -6; y < map->getHeight() + 6; y += 2)
for (int x = -6; x < map->getWidth() + 6; x += 2) {
for (int y = -borderVertDist; y < map->getHeight() + borderVertDist; y += borderHeight)
for (int x = -borderHorzDist; x < map->getWidth() + borderHorzDist; x += borderWidth) {
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
item->setX(x * 16);
item->setY(y * 16);
@ -1346,6 +1354,17 @@ void Editor::displayMapBorder() {
}
}
int Editor::getBorderDrawDistance(int dimension) {
// Draw sufficient border blocks to fill the player's view (BORDER_DISTANCE)
if (dimension >= BORDER_DISTANCE) {
return dimension;
} else if (dimension) {
return dimension * (BORDER_DISTANCE / dimension + (BORDER_DISTANCE % dimension ? 1 : 0));
} else {
return BORDER_DISTANCE;
}
}
void Editor::displayMapGrid() {
for (QGraphicsLineItem* item : gridLines) {
if (item && item->scene()) {

View file

@ -50,7 +50,6 @@ MainWindow::MainWindow(QWidget *parent) :
// Re-initialize everything to a blank slate if opening the recent project failed.
this->initWindow();
}
on_toolButton_Paint_clicked();
}
@ -160,19 +159,38 @@ void MainWindow::setProjectSpecificUIVisibility()
ui->checkBox_AllowRunning->setVisible(false);
ui->checkBox_AllowBiking->setVisible(false);
ui->checkBox_AllowEscapeRope->setVisible(false);
ui->spinBox_FloorNumber->setVisible(false);
ui->label_AllowRunning->setVisible(false);
ui->label_AllowBiking->setVisible(false);
ui->label_AllowEscapeRope->setVisible(false);
ui->label_FloorNumber->setVisible(false);
ui->actionRegion_Map_Editor->setVisible(true);
break;
case BaseGameVersion::pokeemerald:
ui->checkBox_AllowRunning->setVisible(true);
ui->checkBox_AllowBiking->setVisible(true);
ui->checkBox_AllowEscapeRope->setVisible(true);
ui->spinBox_FloorNumber->setVisible(false);
ui->label_AllowRunning->setVisible(true);
ui->label_AllowBiking->setVisible(true);
ui->label_AllowEscapeRope->setVisible(true);
ui->label_FloorNumber->setVisible(false);
ui->actionRegion_Map_Editor->setVisible(true);
break;
case BaseGameVersion::pokefirered:
ui->checkBox_AllowRunning->setVisible(true);
ui->checkBox_AllowBiking->setVisible(true);
ui->checkBox_AllowEscapeRope->setVisible(true);
ui->spinBox_FloorNumber->setVisible(true);
ui->label_AllowRunning->setVisible(true);
ui->label_AllowBiking->setVisible(true);
ui->label_AllowEscapeRope->setVisible(true);
ui->label_FloorNumber->setVisible(true);
ui->newEventToolButton->newWeatherTriggerAction->setVisible(false);
ui->newEventToolButton->newSecretBaseAction->setVisible(false);
// TODO: pokefirered is not set up for the Region Map Editor and vice versa.
// porymap will crash on attempt. Remove below once resolved
ui->actionRegion_Map_Editor->setVisible(false);
break;
}
}
@ -275,6 +293,7 @@ bool MainWindow::openProject(QString dir) {
projectConfig.setProjectDir(dir);
projectConfig.load();
this->closeSupplementaryWindows();
this->setProjectSpecificUIVisibility();
bool already_open = isProjectOpen() && (editor->project->root == dir);
@ -504,6 +523,7 @@ void MainWindow::displayMapProperties() {
ui->checkBox_AllowRunning->setChecked(map->allowRunning.toInt() > 0 || map->allowRunning == "TRUE");
ui->checkBox_AllowBiking->setChecked(map->allowBiking.toInt() > 0 || map->allowBiking == "TRUE");
ui->checkBox_AllowEscapeRope->setChecked(map->allowEscapeRope.toInt() > 0 || map->allowEscapeRope == "TRUE");
ui->spinBox_FloorNumber->setValue(map->floorNumber);
// Custom fields table.
ui->tableWidget_CustomHeaderFields->blockSignals(true);
@ -607,6 +627,13 @@ void MainWindow::on_checkBox_AllowEscapeRope_clicked(bool checked)
}
}
void MainWindow::on_spinBox_FloorNumber_valueChanged(int offset)
{
if (editor && editor->map) {
editor->map->floorNumber = offset;
}
}
bool MainWindow::loadDataStructures() {
Project *project = editor->project;
bool success = project->readMapLayouts()
@ -619,15 +646,18 @@ bool MainWindow::loadDataStructures() {
&& project->readMapTypes()
&& project->readMapBattleScenes()
&& project->readWeatherNames()
&& project->readCoordEventWeatherNames()
&& project->readSecretBaseIds()
&& project->readBgEventFacingDirections()
&& project->readTrainerTypes()
&& project->readMetatileBehaviors()
&& project->readTilesetProperties()
&& project->readHealLocations()
&& project->readMiscellaneousConstants()
&& project->readSpeciesIconPaths()
&& project->readWildMonData();
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeemerald || projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby)
success = success
&& project->readSecretBaseIds()
&& project->readCoordEventWeatherNames();
if (!success) {
return false;
}
@ -969,6 +999,8 @@ void MainWindow::on_actionNew_Tileset_triggered() {
}
mt->behavior = 0;
mt->layerType = 0;
mt->encounterType = 0;
mt->terrainType = 0;
newSet->metatiles->append(mt);
}
@ -1334,6 +1366,7 @@ void MainWindow::updateSelectedObjects() {
QList<EventPropertiesFrame *> frames;
bool pokefirered = projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered;
for (DraggablePixmapItem *item : *events) {
EventPropertiesFrame *frame = new EventPropertiesFrame;
// frame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
@ -1387,17 +1420,20 @@ void MainWindow::updateSelectedObjects() {
field_labels["radius_y"] = "Movement Radius Y";
field_labels["trainer_type"] = "Trainer Type";
field_labels["sight_radius_tree_id"] = "Sight Radius / Berry Tree ID";
field_labels["in_connection"] = "In Connection";
field_labels["destination_warp"] = "Destination Warp";
field_labels["destination_map_name"] = "Destination Map";
field_labels["script_var"] = "Var";
field_labels["script_var_value"] = "Var Value";
field_labels["player_facing_direction"] = "Player Facing Direction";
field_labels["item"] = "Item";
field_labels["item_unknown5"] = "Unknown 5";
field_labels["item_unknown6"] = "Unknown 6";
field_labels["quantity"] = "Quantity";
field_labels["underfoot"] = "Requires Itemfinder";
field_labels["weather"] = "Weather";
field_labels["flag"] = "Flag";
field_labels["secret_base_id"] = "Secret Base Id";
field_labels["respawn_map"] = "Respawn Map";
field_labels["respawn_npc"] = "Respawn NPC";
QStringList fields;
@ -1425,6 +1461,9 @@ void MainWindow::updateSelectedObjects() {
fields << "event_flag";
fields << "trainer_type";
fields << "sight_radius_tree_id";
if (pokefirered) {
fields << "in_connection";
}
}
else if (event_type == EventType::Warp) {
fields << "destination_map_name";
@ -1445,6 +1484,10 @@ void MainWindow::updateSelectedObjects() {
else if (event_type == EventType::HiddenItem) {
fields << "item";
fields << "flag";
if (pokefirered) {
fields << "quantity";
fields << "underfoot";
}
}
else if (event_type == EventType::SecretBase) {
fields << "secret_base_id";
@ -1453,8 +1496,15 @@ void MainWindow::updateSelectedObjects() {
// Hide elevation so users don't get impression that editing it is meaningful.
frame->ui->spinBox_z->setVisible(false);
frame->ui->label_z->setVisible(false);
if (pokefirered) {
fields << "respawn_map";
fields << "respawn_npc";
}
}
// Some keys shouldn't use a combobox
QStringList spinKeys = {"quantity", "respawn_npc"};
QStringList checkKeys = {"underfoot", "in_connection"};
for (QString key : fields) {
QString value = item->event->get(key);
QWidget *widget = new QWidget(frame);
@ -1462,30 +1512,17 @@ void MainWindow::updateSelectedObjects() {
fl->setContentsMargins(9, 0, 9, 0);
fl->setRowWrapPolicy(QFormLayout::WrapLongRows);
NoScrollComboBox *combo = new NoScrollComboBox(widget);
combo->setEditable(true);
NoScrollSpinBox *spin;
NoScrollComboBox *combo;
QCheckBox *check;
// trainer_type has custom values, so it has special signal logic.
if (key == "trainer_type") {
combo->setEditable(false);
combo->addItem("NONE", "0");
combo->addItem("NORMAL", "1");
combo->addItem("SEE ALL DIRECTIONS", "3");
combo->setToolTip("The trainer type of this object event.\n"
"If it is not a trainer, use NONE. SEE ALL DIRECTIONS\n"
"should only be used with a sight radius of 1.");
combo->setMinimumContentsLength(10);
int index = combo->findData(value);
if (index != -1) {
combo->setCurrentIndex(index);
}
fl->addRow(new QLabel(field_labels[key], widget), combo);
widget->setLayout(fl);
frame->layout()->addWidget(widget);
item->bindToUserData(combo, key);
continue;
if (spinKeys.contains(key)) {
spin = new NoScrollSpinBox(widget);
} else if (checkKeys.contains(key)) {
check = new QCheckBox(widget);
} else {
combo = new NoScrollComboBox(widget);
combo->setEditable(true);
}
if (key == "destination_map_name") {
@ -1501,6 +1538,12 @@ void MainWindow::updateSelectedObjects() {
combo->addItem(value);
}
combo->addItems(*editor->project->itemNames);
} else if (key == "quantity") {
spin->setToolTip("The number of items received when the hidden item is picked up.");
// Min 1 not needed. 0 is treated as a valid quantity and works as expected in-game.
spin->setMaximum(127);
} else if (key == "underfoot") {
check->setToolTip("If checked, hidden item can only be picked up using the Itemfinder");
} else if (key == "flag" || key == "event_flag") {
if (!editor->project->flagNames->contains(value)) {
combo->addItem(value);
@ -1564,20 +1607,72 @@ void MainWindow::updateSelectedObjects() {
combo->setMinimumContentsLength(4);
} else if (key == "script_label") {
combo->setToolTip("The script which is executed with this event.");
} else if (key == "trainer_type") {
combo->addItems(*editor->project->trainerTypes);
combo->setToolTip("The trainer type of this object event.\n"
"If it is not a trainer, use NONE. SEE ALL DIRECTIONS\n"
"should only be used with a sight radius of 1.");
} else if (key == "sight_radius_tree_id") {
combo->setToolTip("The maximum sight range of a trainer,\n"
"OR the unique id of the berry tree.");
combo->setMinimumContentsLength(4);
} else if (key == "in_connection") {
check->setToolTip("Check if object is positioned in the connection to another map.");
} else if (key == "respawn_map") {
if (!editor->project->mapNames->contains(value)) {
combo->addItem(value);
}
combo->addItems(*editor->project->mapNames);
combo->setToolTip("The map where the player will respawn after whiteout.");
} else if (key == "respawn_npc") {
spin->setToolTip("event_object ID of the NPC the player interacts with\n"
"upon respawning after whiteout.");
spin->setMinimum(1);
spin->setMaximum(126);
} else {
combo->addItem(value);
}
combo->setCurrentText(value);
fl->addRow(new QLabel(field_labels[key], widget), combo);
widget->setLayout(fl);
frame->layout()->addWidget(widget);
// Keys using spin boxes
if (spinKeys.contains(key)) {
spin->setValue(value.toInt());
item->bind(combo, key);
fl->addRow(new QLabel(field_labels[key], widget), spin);
widget->setLayout(fl);
frame->layout()->addWidget(widget);
connect(spin, QOverload<int>::of(&NoScrollSpinBox::valueChanged), [item, key](int value) {
item->event->put(key, value);
});
// Keys using check boxes
} else if (checkKeys.contains(key)) {
check->setChecked(value.toInt());
fl->addRow(new QLabel(field_labels[key], widget), check);
widget->setLayout(fl);
frame->layout()->addWidget(widget);
connect(check, &QCheckBox::stateChanged, [item, key](int state) {
switch (state)
{
case Qt::Checked:
item->event->put(key, true);
break;
case Qt::Unchecked:
item->event->put(key, false);
break;
}
});
// Keys using combo boxes
} else {
combo->setCurrentText(value);
fl->addRow(new QLabel(field_labels[key], widget), combo);
widget->setLayout(fl);
frame->layout()->addWidget(widget);
item->bind(combo, key);
}
}
// Custom fields table.
@ -2064,7 +2159,7 @@ void MainWindow::on_comboBox_SecondaryTileset_currentTextChanged(const QString &
}
}
void MainWindow::on_pushButton_clicked()
void MainWindow::on_pushButton_ChangeDimensions_clicked()
{
QDialog dialog(this, Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
dialog.setWindowTitle("Change Map Dimensions");
@ -2074,15 +2169,31 @@ void MainWindow::on_pushButton_clicked()
QSpinBox *widthSpinBox = new QSpinBox();
QSpinBox *heightSpinBox = new QSpinBox();
QSpinBox *bwidthSpinBox = new QSpinBox();
QSpinBox *bheightSpinBox = new QSpinBox();
widthSpinBox->setMinimum(1);
heightSpinBox->setMinimum(1);
bwidthSpinBox->setMinimum(1);
bheightSpinBox->setMinimum(1);
// See below for explanation of maximum map dimensions
widthSpinBox->setMaximum(0x1E7);
heightSpinBox->setMaximum(0x1D1);
// Maximum based only on data type (u8) of map border width/height
bwidthSpinBox->setMaximum(255);
bheightSpinBox->setMaximum(255);
widthSpinBox->setValue(editor->map->getWidth());
heightSpinBox->setValue(editor->map->getHeight());
form.addRow(new QLabel("Width"), widthSpinBox);
form.addRow(new QLabel("Height"), heightSpinBox);
bwidthSpinBox->setValue(editor->map->getBorderWidth());
bheightSpinBox->setValue(editor->map->getBorderHeight());
if (projectConfig.getUseCustomBorderSize()) {
form.addRow(new QLabel("Map Width"), widthSpinBox);
form.addRow(new QLabel("Map Height"), heightSpinBox);
form.addRow(new QLabel("Border Width"), bwidthSpinBox);
form.addRow(new QLabel("Border Height"), bheightSpinBox);
} else {
form.addRow(new QLabel("Width"), widthSpinBox);
form.addRow(new QLabel("Height"), heightSpinBox);
}
QLabel *errorLabel = new QLabel();
QPalette errorPalette;
@ -2104,8 +2215,8 @@ void MainWindow::on_pushButton_clicked()
dialog.accept();
} else {
QString errorText = QString("Error: The specified width and height are too large.\n"
"The maximum width and height is the following: (width + 15) * (height + 14) <= 10240\n"
"The specified width and height was: (%1 + 15) * (%2 + 14) = %3")
"The maximum map width and height is the following: (width + 15) * (height + 14) <= 10240\n"
"The specified map width and height was: (%1 + 15) * (%2 + 14) = %3")
.arg(widthSpinBox->value())
.arg(heightSpinBox->value())
.arg(numMetatiles);
@ -2119,6 +2230,7 @@ void MainWindow::on_pushButton_clicked()
if (dialog.exec() == QDialog::Accepted) {
editor->map->setDimensions(widthSpinBox->value(), heightSpinBox->value());
editor->map->setBorderDimensions(bwidthSpinBox->value(), bheightSpinBox->value());
editor->map->commit();
onMapNeedsRedrawing();
}
@ -2299,6 +2411,17 @@ void MainWindow::on_actionRegion_Map_Editor_triggered() {
}
}
void MainWindow::closeSupplementaryWindows() {
if (this->tilesetEditor)
delete this->tilesetEditor;
if (this->regionMapEditor)
delete this->regionMapEditor;
if (this->mapImageExporter)
delete this->mapImageExporter;
if (this->newmapprompt)
delete this->newmapprompt;
}
void MainWindow::closeEvent(QCloseEvent *event) {
if (projectHasUnsavedChanges || editor->map->hasUnsavedChanges()) {
QMessageBox::StandardButton result = QMessageBox::question(

View file

@ -8,6 +8,7 @@
#include "tile.h"
#include "tileset.h"
#include "imageexport.h"
#include "map.h"
#include "orderedjson.h"
@ -48,6 +49,7 @@ Project::Project()
coordEventWeatherNames = new QStringList;
secretBaseIds = new QStringList;
bgEventFacingDirections = new QStringList;
trainerTypes = new QStringList;
map_cache = new QMap<QString, Map*>;
mapConstantsToMapNames = new QMap<QString, QString>;
mapNamesToMapConstants = new QMap<QString, QString>;
@ -105,8 +107,8 @@ QMap<QString, bool> Project::getTopLevelMapFields() {
{"requires_flash", true},
{"weather", true},
{"map_type", true},
{"allow_bike", true},
{"allow_escape_rope", true},
{"allow_cycling", true},
{"allow_escaping", true},
{"allow_running", true},
{"show_map_name", true},
{"battle_scene", true},
@ -118,6 +120,31 @@ QMap<QString, bool> Project::getTopLevelMapFields() {
{"shared_events_map", true},
{"shared_scripts_map", true},
};
} else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
return QMap<QString, bool>
{
{"id", true},
{"name", true},
{"layout", true},
{"music", true},
{"region_map_section", true},
{"requires_flash", true},
{"weather", true},
{"map_type", true},
{"allow_cycling", true},
{"allow_escaping", true},
{"allow_running", true},
{"show_map_name", true},
{"floor_number", true},
{"battle_scene", true},
{"connections", true},
{"object_events", true},
{"warp_events", true},
{"coord_events", true},
{"bg_events", true},
{"shared_events_map", true},
{"shared_scripts_map", true},
};
} else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) {
return QMap<QString, bool>
{
@ -169,9 +196,14 @@ bool Project::loadMapData(Map* map) {
map->show_location = QString::number(mapObj["show_map_name"].toBool());
map->battle_scene = mapObj["battle_scene"].toString();
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeemerald) {
map->allowBiking = QString::number(mapObj["allow_bike"].toBool());
map->allowEscapeRope = QString::number(mapObj["allow_escape_rope"].toBool());
map->allowBiking = QString::number(mapObj["allow_cycling"].toBool());
map->allowEscapeRope = QString::number(mapObj["allow_escaping"].toBool());
map->allowRunning = QString::number(mapObj["allow_running"].toBool());
} else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
map->allowBiking = QString::number(mapObj["allow_cycling"].toBool());
map->allowEscapeRope = QString::number(mapObj["allow_escaping"].toBool());
map->allowRunning = QString::number(mapObj["allow_running"].toBool());
map->floorNumber = mapObj["floor_number"].toInt();
}
map->sharedEventsMap = mapObj["shared_events_map"].toString();
map->sharedScriptsMap = mapObj["shared_scripts_map"].toString();
@ -184,6 +216,9 @@ bool Project::loadMapData(Map* map) {
Event *object = new Event(event, EventType::Object);
object->put("map_name", map->name);
object->put("sprite", event["graphics_id"].toString());
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
object->put("in_connection", event["in_connection"].toBool());
}
object->put("x", QString::number(event["x"].toInt()));
object->put("y", QString::number(event["y"].toInt()));
object->put("elevation", QString::number(event["elevation"].toInt()));
@ -230,17 +265,22 @@ bool Project::loadMapData(Map* map) {
HealLocation loc = *it;
//if TRUE map is flyable / has healing location
if (loc.name == QString(mapNamesToMapConstants->value(map->name)).remove(0,4)) {
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.name);
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", "heal_event_group");
heal->put("event_type", EventType::HealLocation);
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
heal->put("respawn_map", mapConstantsToMapNames->value(QString("MAP_" + loc.respawnMap)));
heal->put("respawn_npc", loc.respawnNPC);
}
map->events["heal_event_group"].append(heal);
}
@ -300,6 +340,10 @@ bool Project::loadMapData(Map* map) {
bg->put("elevation", QString::number(event["elevation"].toInt()));
bg->put("item", event["item"].toString());
bg->put("flag", event["flag"].toString());
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
bg->put("quantity", event["quantity"].toInt());
bg->put("underfoot", event["underfoot"].toBool());
}
bg->put("event_group_type", "bg_event_group");
map->events["bg_event_group"].append(bg);
} else if (type == "secret_base") {
@ -378,12 +422,12 @@ QString Project::readMapLocation(QString map_name) {
}
void Project::setNewMapHeader(Map* map, int mapIndex) {
map->song = "MUS_DAN02";
map->layoutId = QString("%1").arg(mapIndex);
map->location = "MAPSEC_LITTLEROOT_TOWN";
map->location = mapSectionValueToName.value(0);
map->requiresFlash = "FALSE";
map->weather = "WEATHER_SUNNY";
map->type = "MAP_TYPE_TOWN";
map->weather = weatherNames->value(0, "WEATHER_NONE");
map->type = mapTypes->value(0, "MAP_TYPE_NONE");
map->song = defaultSong;
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) {
map->show_location = "TRUE";
} else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeemerald) {
@ -391,9 +435,15 @@ void Project::setNewMapHeader(Map* map, int mapIndex) {
map->allowEscapeRope = "0";
map->allowRunning = "1";
map->show_location = "1";
} else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
map->allowBiking = "1";
map->allowEscapeRope = "0";
map->allowRunning = "1";
map->show_location = "1";
map->floorNumber = 0;
}
map->battle_scene = "MAP_BATTLE_SCENE_NORMAL";
map->battle_scene = mapBattleScenes->value(0, "MAP_BATTLE_SCENE_NORMAL");
}
bool Project::loadMapLayout(Map* map) {
@ -408,9 +458,14 @@ bool Project::loadMapLayout(Map* map) {
return false;
}
return loadMapTilesets(map)
&& loadBlockdata(map)
&& loadMapBorder(map);
// Force these to run even if one fails
bool loadedTilesets = loadMapTilesets(map);
bool loadedBlockdata = loadBlockdata(map);
bool loadedBorder = loadMapBorder(map);
return loadedTilesets
&& loadedBlockdata
&& loadedBorder;
}
bool Project::readMapLayouts() {
@ -449,8 +504,15 @@ bool Project::readMapLayouts() {
"border_filepath",
"blockdata_filepath",
};
bool useCustomBorderSize = projectConfig.getUseCustomBorderSize();
if (useCustomBorderSize) {
requiredFields.append("border_width");
requiredFields.append("border_height");
}
for (int i = 0; i < layouts.size(); i++) {
QJsonObject layoutObj = layouts[i].toObject();
if (layoutObj.isEmpty())
continue;
if (!parser.ensureFieldsExist(layoutObj, requiredFields)) {
logError(QString("Layout %1 is missing field(s) in %2.").arg(i).arg(layoutsFilepath));
return false;
@ -478,6 +540,23 @@ bool Project::readMapLayouts() {
return false;
}
layout->height = QString::number(lheight);
if (useCustomBorderSize) {
int bwidth = layoutObj["border_width"].toInt();
if (bwidth <= 0) { // 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG
logWarn(QString("Invalid layout 'border_width' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bwidth).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_WIDTH));
bwidth = DEFAULT_BORDER_WIDTH;
}
layout->border_width = QString::number(bwidth);
int bheight = layoutObj["border_height"].toInt();
if (bheight <= 0) {
logWarn(QString("Invalid layout 'border_height' value '%1' on layout %2 in %3. Must be greater than 0. Using default (%4) instead.").arg(bheight).arg(i).arg(layoutsFilepath).arg(DEFAULT_BORDER_HEIGHT));
bheight = DEFAULT_BORDER_HEIGHT;
}
layout->border_height = QString::number(bheight);
} else {
layout->border_width = QString::number(DEFAULT_BORDER_WIDTH);
layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT);
}
layout->tileset_primary_label = layoutObj["primary_tileset"].toString();
if (layout->tileset_primary_label.isEmpty()) {
logError(QString("Missing 'primary_tileset' value on layout %1 in %2").arg(i).arg(layoutsFilepath));
@ -521,6 +600,7 @@ void Project::saveMapLayouts() {
OrderedJson::object layoutsObj;
layoutsObj["layouts_table_label"] = layoutsLabel;
bool useCustomBorderSize = projectConfig.getUseCustomBorderSize();
OrderedJson::array layoutsArr;
for (QString layoutId : mapLayoutsTableMaster) {
MapLayout *layout = mapLayouts.value(layoutId);
@ -529,6 +609,10 @@ void Project::saveMapLayouts() {
layoutObj["name"] = layout->name;
layoutObj["width"] = layout->width.toInt(nullptr, 0);
layoutObj["height"] = layout->height.toInt(nullptr, 0);
if (useCustomBorderSize) {
layoutObj["border_width"] = layout->border_width.toInt(nullptr, 0);
layoutObj["border_height"] = layout->border_height.toInt(nullptr, 0);
}
layoutObj["primary_tileset"] = layout->tileset_primary_label;
layoutObj["secondary_tileset"] = layout->tileset_secondary_label;
layoutObj["border_filepath"] = layout->border_path;
@ -549,10 +633,12 @@ void Project::setNewMapLayout(Map* map) {
layout->name = QString("%1_Layout").arg(map->name);
layout->width = "20";
layout->height = "20";
layout->border_width = DEFAULT_BORDER_WIDTH;
layout->border_height = DEFAULT_BORDER_HEIGHT;
layout->border_path = QString("data/layouts/%1/border.bin").arg(map->name);
layout->blockdata_path = QString("data/layouts/%1/map.bin").arg(map->name);
layout->tileset_primary_label = "gTileset_General";
layout->tileset_secondary_label = "gTileset_Petalburg";
layout->tileset_primary_label = tilesetLabels["primary"].value(0, "gTileset_General");
layout->tileset_secondary_label = tilesetLabels["secondary"].value(0, projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered ? "gTileset_PalletTown" : "gTileset_Petalburg");
map->layout = layout;
map->layoutId = layout->id;
@ -716,9 +802,19 @@ void Project::saveMapConstantsHeader() {
// saves heal location coords in root + /src/data/heal_locations.h
// and indexes as defines in root + /include/constants/heal_locations.h
void Project::saveHealLocationStruct(Map *map) {
QString data_text = QString("%1%2struct HealLocation sHealLocations[] =\n{\n")
QString constantPrefix, arrayName;
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
constantPrefix = "SPAWN_";
arrayName = "sSpawnPoints";
} else {
constantPrefix = "HEAL_LOCATION_";
arrayName = "sHealLocations";
}
QString data_text = QString("%1%2struct HealLocation %3[] =\n{\n")
.arg(dataQualifiers.value("heal_locations").isStatic ? "static " : "")
.arg(dataQualifiers.value("heal_locations").isConst ? "const " : "");
.arg(dataQualifiers.value("heal_locations").isConst ? "const " : "")
.arg(arrayName);
QString constants_text = QString("#ifndef GUARD_CONSTANTS_HEAL_LOCATIONS_H\n");
constants_text += QString("#define GUARD_CONSTANTS_HEAL_LOCATIONS_H\n\n");
@ -729,7 +825,7 @@ void Project::saveHealLocationStruct(Map *map) {
// set flyableMapsDupes and flyableMapsUnique
for (auto it = flyableMaps.begin(); it != flyableMaps.end(); it++) {
HealLocation loc = *it;
QString xname = loc.name;
QString xname = loc.idName;
if (flyableMapsUnique.contains(xname)) {
flyableMapsDupes[xname] = 1;
}
@ -745,33 +841,58 @@ void Project::saveHealLocationStruct(Map *map) {
}
int i = 1;
for (auto map_in : flyableMaps) {
data_text += QString(" {MAP_GROUP(%1), MAP_NUM(%1), %2, %3},\n")
.arg(map_in.name)
// add numbered suffix for duplicate constants
if (flyableMapsDupes.keys().contains(map_in.idName)) {
map_in.idName += QString("_%1").arg(flyableMapsDupes[map_in.idName]);
flyableMapsDupes[map_in.idName]++;
}
// Save first array (heal location coords), only data array in RSE
data_text += QString(" [%1%2 - 1] = {MAP_GROUP(%3), MAP_NUM(%3), %4, %5},\n")
.arg(constantPrefix)
.arg(map_in.idName)
.arg(map_in.mapName)
.arg(map_in.x)
.arg(map_in.y);
QString ending = QString("");
// must add _1 / _2 for maps that have duplicates
if (flyableMapsDupes.keys().contains(map_in.name)) {
// map contains multiple heal locations
ending += QString("_%1").arg(flyableMapsDupes[map_in.name]);
flyableMapsDupes[map_in.name]++;
}
// Save constants
if (map_in.index != 0) {
constants_text += QString("#define HEAL_LOCATION_%1 %2\n")
.arg(map_in.name + ending)
constants_text += QString("#define %1%2 %3\n")
.arg(constantPrefix)
.arg(map_in.idName)
.arg(map_in.index);
}
else {
constants_text += QString("#define HEAL_LOCATION_%1 %2\n")
.arg(map_in.name + ending)
} else {
constants_text += QString("#define %1%2 %3\n")
.arg(constantPrefix)
.arg(map_in.idName)
.arg(i);
}
i++;
}
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
// Save second array (map where player respawns for each heal location)
data_text += QString("};\n\n%1%2u16 sWhiteoutRespawnHealCenterMapIdxs[][2] =\n{\n")
.arg(dataQualifiers.value("heal_locations").isStatic ? "static " : "")
.arg(dataQualifiers.value("heal_locations").isConst ? "const " : "");
for (auto map_in : flyableMaps) {
data_text += QString(" [%1%2 - 1] = {MAP_GROUP(%3), MAP_NUM(%3)},\n")
.arg(constantPrefix)
.arg(map_in.idName)
.arg(map_in.respawnMap);
}
// Save third array (object id of NPC player speaks to upon respawning for each heal location)
data_text += QString("};\n\n%1%2u8 sWhiteoutRespawnHealerNpcIds[] =\n{\n")
.arg(dataQualifiers.value("heal_locations").isStatic ? "static " : "")
.arg(dataQualifiers.value("heal_locations").isConst ? "const " : "");
for (auto map_in : flyableMaps) {
data_text += QString(" [%1%2 - 1] = %3,\n")
.arg(constantPrefix)
.arg(map_in.idName)
.arg(map_in.respawnNPC);
}
}
data_text += QString("};\n");
constants_text += QString("\n#endif // GUARD_CONSTANTS_HEAL_LOCATIONS_H\n");
@ -876,9 +997,21 @@ void Project::saveTilesetMetatileAttributes(Tileset *tileset) {
QFile attrs_file(tileset->metatile_attrs_path);
if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QByteArray data;
for (Metatile *metatile : *tileset->metatiles) {
data.append(static_cast<char>(metatile->behavior));
data.append(static_cast<char>((metatile->layerType << 4) & 0xF0));
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
for (Metatile *metatile : *tileset->metatiles) {
data.append(static_cast<char>(metatile->behavior));
data.append(static_cast<char>(metatile->behavior >> 8) |
static_cast<char>(metatile->terrainType << 1));
data.append(static_cast<char>(0));
data.append(static_cast<char>(metatile->encounterType) |
static_cast<char>(metatile->layerType << 5));
}
} else {
for (Metatile *metatile : *tileset->metatiles) {
data.append(static_cast<char>(metatile->behavior));
data.append(static_cast<char>((metatile->layerType << 4) & 0xF0));
}
}
attrs_file.write(data);
} else {
@ -927,14 +1060,26 @@ bool Project::loadMapTilesets(Map* map) {
map->layout->tileset_primary = getTileset(map->layout->tileset_primary_label);
if (!map->layout->tileset_primary) {
logError(QString("Map layout %1 has invalid primary tileset '%2'").arg(map->layout->id).arg(map->layout->tileset_primary_label));
return false;
QString defaultTileset = tilesetLabels["primary"].value(0, "gTileset_General");
logWarn(QString("Map layout %1 has invalid primary tileset '%2'. Using default '%3'").arg(map->layout->id).arg(map->layout->tileset_primary_label).arg(defaultTileset));
map->layout->tileset_primary_label = defaultTileset;
map->layout->tileset_primary = getTileset(map->layout->tileset_primary_label);
if (!map->layout->tileset_primary) {
logError(QString("Failed to set default primary tileset."));
return false;
}
}
map->layout->tileset_secondary = getTileset(map->layout->tileset_secondary_label);
if (!map->layout->tileset_secondary) {
logError(QString("Map layout %1 has invalid secondary tileset '%2'").arg(map->layout->id).arg(map->layout->tileset_secondary_label));
return false;
QString defaultTileset = tilesetLabels["secondary"].value(0, projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered ? "gTileset_PalletTown" : "gTileset_Petalburg");
logWarn(QString("Map layout %1 has invalid secondary tileset '%2'. Using default '%3'").arg(map->layout->id).arg(map->layout->tileset_secondary_label).arg(defaultTileset));
map->layout->tileset_secondary_label = defaultTileset;
map->layout->tileset_secondary = getTileset(map->layout->tileset_secondary_label);
if (!map->layout->tileset_secondary) {
logError(QString("Failed to set default secondary tileset."));
return false;
}
}
return true;
}
@ -954,8 +1099,13 @@ Tileset* Project::loadTileset(QString label, Tileset *tileset) {
tileset->tiles_label = values->value(3);
tileset->palettes_label = values->value(4);
tileset->metatiles_label = values->value(5);
tileset->metatile_attrs_label = values->value(6);
tileset->callback_label = values->value(7);
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
tileset->callback_label = values->value(6);
tileset->metatile_attrs_label = values->value(7);
} else {
tileset->metatile_attrs_label = values->value(6);
tileset->callback_label = values->value(7);
}
loadTilesetAssets(tileset);
@ -997,7 +1147,7 @@ bool Project::loadMapBorder(Map *map) {
QString path = QString("%1/%2").arg(root).arg(map->layout->border_path);
map->layout->border = readBlockdata(path);
int borderLength = 4;
int borderLength = map->getBorderWidth() * map->getBorderHeight();
if (map->layout->border->blocks->count() != borderLength) {
logWarn(QString("Layout border blockdata length %1 must be %2. Resizing border blockdata.")
.arg(map->layout->border->blocks->count())
@ -1009,10 +1159,21 @@ bool Project::loadMapBorder(Map *map) {
void Project::setNewMapBorder(Map *map) {
Blockdata *blockdata = new Blockdata;
blockdata->addBlock(qint16(0x01D4));
blockdata->addBlock(qint16(0x01D5));
blockdata->addBlock(qint16(0x01DC));
blockdata->addBlock(qint16(0x01DD));
if (map->getBorderWidth() != DEFAULT_BORDER_WIDTH || map->getBorderHeight() != DEFAULT_BORDER_HEIGHT) {
for (int i = 0; i < map->getBorderWidth() * map->getBorderHeight(); i++) {
blockdata->addBlock(0);
}
} else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
blockdata->addBlock(qint16(0x0014));
blockdata->addBlock(qint16(0x0015));
blockdata->addBlock(qint16(0x001C));
blockdata->addBlock(qint16(0x001D));
} else {
blockdata->addBlock(qint16(0x01D4));
blockdata->addBlock(qint16(0x01D5));
blockdata->addBlock(qint16(0x01DC));
blockdata->addBlock(qint16(0x01DD));
}
map->layout->border = blockdata;
}
@ -1058,14 +1219,14 @@ void Project::saveMap(Map *map) {
QString text = this->getScriptDefaultString(projectConfig.getUsePoryScript(), map->name);
saveTextFile(root + "/data/maps/" + map->name + "/scripts" + this->getScriptFileExtension(projectConfig.getUsePoryScript()), text);
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) {
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby || projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
// Create file data/maps/<map_name>/text.inc
saveTextFile(root + "/data/maps/" + map->name + "/text" + this->getScriptFileExtension(projectConfig.getUsePoryScript()), "\n");
}
// Simply append to data/event_scripts.s.
text = QString("\n\t.include \"data/maps/%1/scripts.inc\"\n").arg(map->name);
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby) {
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokeruby || projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
text += QString("\t.include \"data/maps/%1/text.inc\"\n").arg(map->name);
}
appendTextFile(root + "/data/event_scripts.s", text);
@ -1099,6 +1260,10 @@ void Project::saveMap(Map *map) {
newLayoutObj["name"] = map->layout->name;
newLayoutObj["width"] = map->layout->width.toInt();
newLayoutObj["height"] = map->layout->height.toInt();
if (projectConfig.getUseCustomBorderSize()) {
newLayoutObj["border_width"] = map->layout->border_width.toInt();
newLayoutObj["border_height"] = map->layout->border_height.toInt();
}
newLayoutObj["primary_tileset"] = map->layout->tileset_primary_label;
newLayoutObj["secondary_tileset"] = map->layout->tileset_secondary_label;
newLayoutObj["border_filepath"] = map->layout->border_path;
@ -1125,10 +1290,13 @@ void Project::saveMap(Map *map) {
mapObj["requires_flash"] = map->requiresFlash.toInt() > 0 || map->requiresFlash == "TRUE";
mapObj["weather"] = map->weather;
mapObj["map_type"] = map->type;
mapObj["allow_bike"] = map->allowBiking.toInt() > 0 || map->allowBiking == "TRUE";
mapObj["allow_escape_rope"] = map->allowEscapeRope.toInt() > 0 || map->allowEscapeRope == "TRUE";
mapObj["allow_cycling"] = map->allowBiking.toInt() > 0 || map->allowBiking == "TRUE";
mapObj["allow_escaping"] = map->allowEscapeRope.toInt() > 0 || map->allowEscapeRope == "TRUE";
mapObj["allow_running"] = map->allowRunning.toInt() > 0 || map->allowRunning == "TRUE";
mapObj["show_map_name"] = map->show_location.toInt() > 0 || map->show_location == "TRUE";
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
mapObj["floor_number"] = map->floorNumber;
}
mapObj["battle_scene"] = map->battle_scene;
// Connections
@ -1254,8 +1422,9 @@ void Project::loadTilesetAssets(Tileset* tileset) {
if (tileset->name.isNull()) {
return;
}
QRegularExpression re("([a-z])([A-Z0-9])");
QString tilesetName = tileset->name;
QString dir_path = root + "/data/tilesets/" + category + "/" + tilesetName.replace("gTileset_", "").toLower();
QString dir_path = root + "/data/tilesets/" + category + "/" + tilesetName.replace("gTileset_", "").replace(re, "\\1_\\2").toLower();
QList<QStringList> *graphics = parser.parseAsm("data/tilesets/graphics.inc");
QStringList *tiles_values = parser.getLabelValues(graphics, tileset->tiles_label);
@ -1394,16 +1563,43 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
if (attrs_file.open(QIODevice::ReadOnly)) {
QByteArray data = attrs_file.readAll();
int num_metatiles = tileset->metatiles->count();
int num_metatileAttrs = data.length() / 2;
if (num_metatiles != num_metatileAttrs) {
logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(num_metatiles).arg(num_metatileAttrs).arg(tileset->name));
if (num_metatileAttrs > num_metatiles)
num_metatileAttrs = num_metatiles;
}
for (int i = 0; i < num_metatileAttrs; i++) {
int value = (static_cast<unsigned char>(data.at(i * 2 + 1)) << 8) | static_cast<unsigned char>(data.at(i * 2));
tileset->metatiles->at(i)->behavior = value & 0xFF;
tileset->metatiles->at(i)->layerType = (value & 0xF000) >> 12;
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
int num_metatileAttrs = data.length() / 4;
if (num_metatiles != num_metatileAttrs) {
logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(num_metatiles).arg(num_metatileAttrs).arg(tileset->name));
if (num_metatileAttrs > num_metatiles)
num_metatileAttrs = num_metatiles;
}
bool unusedAttribute = false;
for (int i = 0; i < num_metatileAttrs; i++) {
int value = (static_cast<unsigned char>(data.at(i * 4 + 3)) << 24) |
(static_cast<unsigned char>(data.at(i * 4 + 2)) << 16) |
(static_cast<unsigned char>(data.at(i * 4 + 1)) << 8) |
(static_cast<unsigned char>(data.at(i * 4 + 0)));
tileset->metatiles->at(i)->behavior = value & 0x1FF;
tileset->metatiles->at(i)->terrainType = (value & 0x3E00) >> 9;
tileset->metatiles->at(i)->encounterType = (value & 0x7000000) >> 24;
tileset->metatiles->at(i)->layerType = (value & 0x60000000) >> 29;
if (value & ~(0x67003FFF))
unusedAttribute = true;
}
if (unusedAttribute)
logWarn(QString("Unrecognized metatile attributes in %1 will not be saved.").arg(tileset->metatile_attrs_path));
} else {
int num_metatileAttrs = data.length() / 2;
if (num_metatiles != num_metatileAttrs) {
logWarn(QString("Metatile count %1 does not match metatile attribute count %2 in %3").arg(num_metatiles).arg(num_metatileAttrs).arg(tileset->name));
if (num_metatileAttrs > num_metatiles)
num_metatileAttrs = num_metatiles;
}
for (int i = 0; i < num_metatileAttrs; i++) {
int value = (static_cast<unsigned char>(data.at(i * 2 + 1)) << 8) | static_cast<unsigned char>(data.at(i * 2));
tileset->metatiles->at(i)->behavior = value & 0xFF;
tileset->metatiles->at(i)->layerType = (value & 0xF000) >> 12;
tileset->metatiles->at(i)->encounterType = 0;
tileset->metatiles->at(i)->terrainType = 0;
}
}
} else {
logError(QString("Could not open tileset metatile attributes file '%1'").arg(tileset->metatile_attrs_path));
@ -1812,21 +2008,46 @@ bool Project::readRegionMapSections() {
bool Project::readHealLocations() {
dataQualifiers.clear();
flyableMaps.clear();
QString filename = "src/data/heal_locations.h";
QString text = parser.readTextFile(root + "/" + filename);
text.replace(QRegularExpression("//.*?(\r\n?|\n)|/\\*.*?\\*/", QRegularExpression::DotMatchesEverythingOption), "");
dataQualifiers.insert("heal_locations", getDataQualifiers(text, "sHealLocations"));
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
dataQualifiers.insert("heal_locations", getDataQualifiers(text, "sSpawnPoints"));
QRegularExpression spawnRegex("SPAWN_(?<id>[A-Za-z0-9_]+)\\s*- 1\\]\\s* = \\{MAP_GROUP[\\(\\s]+(?<map>[A-Za-z0-9_]+)[\\s\\)]+,\\s*MAP_NUM[\\(\\s]+(\\2)[\\s\\)]+,\\s*(?<x>[0-9A-Fa-fx]+),\\s*(?<y>[0-9A-Fa-fx]+)");
QRegularExpression respawnMapRegex("SPAWN_(?<id>[A-Za-z0-9_]+)\\s*- 1\\]\\s* = \\{MAP_GROUP[\\(\\s]+(?<map>[A-Za-z0-9_]+)[\\s\\)]+,\\s*MAP_NUM[\\(\\s]+(\\2)[\\s\\)]+}");
QRegularExpression respawnNPCRegex("SPAWN_(?<id>[A-Za-z0-9_]+)\\s*- 1\\]\\s* = (?<npc>[0-9]+)");
QRegularExpressionMatchIterator spawns = spawnRegex.globalMatch(text);
QRegularExpressionMatchIterator respawnMaps = respawnMapRegex.globalMatch(text);
QRegularExpressionMatchIterator respawnNPCs = respawnNPCRegex.globalMatch(text);
QRegularExpression regex("MAP_GROUP[\\(\\s]+(?<map>[A-Za-z0-9_]+)[\\s\\)]+,\\s*MAP_NUM[\\(\\s]+(\\1)[\\s\\)]+,\\s*(?<x>[0-9A-Fa-fx]+),\\s*(?<y>[0-9A-Fa-fx]+)");
QRegularExpressionMatchIterator iter = regex.globalMatch(text);
for (int i = 1; iter.hasNext(); i++) {
QRegularExpressionMatch match = iter.next();
QString mapName = match.captured("map");
unsigned x = match.captured("x").toUShort();
unsigned y = match.captured("y").toUShort();
flyableMaps.append(HealLocation(mapName, i, x, y));
// This would be better if idName was used to look up data from the other two arrays
// As it is, element total and order needs to be the same in the 3 arrays to work. This should always be true though
for (int i = 1; spawns.hasNext(); i++) {
QRegularExpressionMatch spawn = spawns.next();
QRegularExpressionMatch respawnMap = respawnMaps.next();
QRegularExpressionMatch respawnNPC = respawnNPCs.next();
QString idName = spawn.captured("id");
QString mapName = spawn.captured("map");
QString respawnMapName = respawnMap.captured("map");
unsigned x = spawn.captured("x").toUShort();
unsigned y = spawn.captured("y").toUShort();
unsigned npc = respawnNPC.captured("npc").toUShort();
flyableMaps.append(HealLocation(idName, mapName, i, x, y, respawnMapName, npc));
}
} else {
dataQualifiers.insert("heal_locations", getDataQualifiers(text, "sHealLocations"));
QRegularExpression regex("HEAL_LOCATION_(?<id>[A-Za-z0-9_]+)\\s*- 1\\]\\s* = \\{MAP_GROUP[\\(\\s]+(?<map>[A-Za-z0-9_]+)[\\s\\)]+,\\s*MAP_NUM[\\(\\s]+(\\2)[\\s\\)]+,\\s*(?<x>[0-9A-Fa-fx]+),\\s*(?<y>[0-9A-Fa-fx]+)");
QRegularExpressionMatchIterator iter = regex.globalMatch(text);
for (int i = 1; iter.hasNext(); i++) {
QRegularExpressionMatch match = iter.next();
QString idName = match.captured("id");
QString mapName = match.captured("map");
unsigned x = match.captured("x").toUShort();
unsigned y = match.captured("y").toUShort();
flyableMaps.append(HealLocation(idName, mapName, i, x, y));
}
}
return true;
}
@ -1961,6 +2182,18 @@ bool Project::readBgEventFacingDirections() {
return true;
}
bool Project::readTrainerTypes() {
trainerTypes->clear();
QStringList prefixes = (QStringList() << "TRAINER_TYPE_");
QString filename = "include/constants/trainer_types.h";
parser.readCDefinesSorted(filename, prefixes, trainerTypes);
if (trainerTypes->isEmpty()) {
logError(QString("Failed to read trainer type constants from %1").arg(filename));
return false;
}
return true;
}
bool Project::readMetatileBehaviors() {
this->metatileBehaviorMap.clear();
this->metatileBehaviorMapInverse.clear();
@ -1969,7 +2202,7 @@ bool Project::readMetatileBehaviors() {
QString filename = "include/constants/metatile_behaviors.h";
this->metatileBehaviorMap = parser.readCDefines(filename, prefixes);
if (this->metatileBehaviorMap.isEmpty()) {
logError(QString("Failed to metatile behaviors from %1.").arg(filename));
logError(QString("Failed to read metatile behaviors from %1.").arg(filename));
return false;
}
@ -1984,6 +2217,7 @@ QStringList Project::getSongNames() {
songDefinePrefixes << "SE_" << "MUS_";
QMap<QString, int> songDefines = parser.readCDefines("include/constants/songs.h", songDefinePrefixes);
QStringList names = songDefines.keys();
this->defaultSong = names.value(0, "MUS_DUMMY");
return names;
}
@ -2085,16 +2319,19 @@ void Project::loadEventPixmaps(QList<Event*> objects) {
QImage spritesheet(root + "/" + path);
if (!spritesheet.isNull()) {
// Infer the sprite dimensions from the OAM labels.
int spriteWidth = spritesheet.width();
int spriteHeight = spritesheet.height();
int spriteWidth, spriteHeight;
QRegularExpression re("\\S+_(\\d+)x(\\d+)");
QRegularExpressionMatch dimensionMatch = re.match(dimensions_label);
if (dimensionMatch.hasMatch()) {
QRegularExpressionMatch oamTablesMatch = re.match(subsprites_label);
if (oamTablesMatch.hasMatch()) {
spriteWidth = dimensionMatch.captured(1).toInt();
spriteHeight = dimensionMatch.captured(2).toInt();
}
QRegularExpressionMatch oamTablesMatch = re.match(subsprites_label);
if (oamTablesMatch.hasMatch()) {
spriteWidth = oamTablesMatch.captured(1).toInt();
spriteHeight = oamTablesMatch.captured(2).toInt();
} else if (dimensionMatch.hasMatch()) {
spriteWidth = dimensionMatch.captured(1).toInt();
spriteHeight = dimensionMatch.captured(2).toInt();
} else {
spriteWidth = spritesheet.width();
spriteHeight = spritesheet.height();
}
object->setPixmapFromSpritesheet(spritesheet, spriteWidth, spriteHeight, object->frame, object->hFlip);
}

View file

@ -8,10 +8,12 @@ void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
QPointF pos = event->pos();
int x = static_cast<int>(pos.x()) / 16;
int y = static_cast<int>(pos.y()) / 16;
int width = map->getBorderWidth();
int height = map->getBorderHeight();
for (int i = 0; i < selectionDimensions.x() && (i + x) < 2; i++) {
for (int j = 0; j < selectionDimensions.y() && (j + y) < 2; j++) {
int blockIndex = (j + y) * 2 + (i + x);
for (int i = 0; i < selectionDimensions.x() && (i + x) < width; i++) {
for (int j = 0; j < selectionDimensions.y() && (j + y) < height; j++) {
int blockIndex = (j + y) * width + (i + x);
uint16_t tile = selectedMetatiles->at(j * selectionDimensions.x() + i);
(*map->layout->border->blocks)[blockIndex].tile = tile;
}
@ -22,15 +24,17 @@ void BorderMetatilesPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
}
void BorderMetatilesPixmapItem::draw() {
QImage image(32, 32, QImage::Format_RGBA8888);
int width = map->getBorderWidth();
int height = map->getBorderHeight();
QImage image(16 * width, 16 * height, QImage::Format_RGBA8888);
QPainter painter(&image);
QVector<Block> *blocks = map->layout->border->blocks;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int x = i * 16;
int y = j * 16;
int index = j * 2 + i;
int index = j * width + i;
QImage metatile_image = getMetatileImage(blocks->value(index).tile, map->layout->tileset_primary, map->layout->tileset_secondary);
QPoint metatile_origin = QPoint(x, y);
painter.drawImage(metatile_origin, metatile_image);
@ -38,5 +42,6 @@ void BorderMetatilesPixmapItem::draw() {
}
painter.end();
map->commit();
this->setPixmap(QPixmap::fromImage(image));
}

View file

@ -70,7 +70,7 @@ void MapImageExporter::updatePreview() {
int borderHeight = 0, borderWidth = 0;
bool forceDrawBorder = showUpConnections || showDownConnections || showLeftConnections || showRightConnections;
if (showBorder || forceDrawBorder) {
borderHeight = 32 * 3, borderWidth = 32 * 3;
borderHeight = BORDER_DISTANCE * 16, borderWidth = BORDER_DISTANCE * 16;
QPixmap newPreview = QPixmap(map->pixmap.width() + borderWidth * 2, map->pixmap.height() + borderHeight * 2);
QPainter borderPainter(&newPreview);
for (auto borderItem : editor->borderItems) {

View file

@ -62,11 +62,15 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) {
ui->comboBox_NewMap_Secondary_Tileset->setCurrentText(project->mapLayouts.value(layoutId)->tileset_secondary_label);
ui->spinBox_NewMap_Width->setDisabled(true);
ui->spinBox_NewMap_Height->setDisabled(true);
ui->spinBox_NewMap_BorderWidth->setDisabled(true);
ui->spinBox_NewMap_BorderHeight->setDisabled(true);
ui->comboBox_NewMap_Primary_Tileset->setDisabled(true);
ui->comboBox_NewMap_Secondary_Tileset->setDisabled(true);
} else {
ui->spinBox_NewMap_Width->setValue(20);
ui->spinBox_NewMap_Height->setValue(20);
ui->spinBox_NewMap_BorderWidth->setValue(DEFAULT_BORDER_WIDTH);
ui->spinBox_NewMap_BorderHeight->setValue(DEFAULT_BORDER_HEIGHT);
}
ui->comboBox_NewMap_Type->addItems(*project->mapTypes);
@ -81,21 +85,44 @@ void NewMapPopup::setDefaultValues(int groupNum, QString mapSec) {
ui->checkBox_NewMap_Allow_Running->setVisible(false);
ui->checkBox_NewMap_Allow_Biking->setVisible(false);
ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(false);
ui->spinBox_NewMap_Floor_Number->setVisible(false);
ui->label_NewMap_Allow_Running->setVisible(false);
ui->label_NewMap_Allow_Biking->setVisible(false);
ui->label_NewMap_Allow_Escape_Rope->setVisible(false);
ui->label_NewMap_Floor_Number->setVisible(false);
break;
case BaseGameVersion::pokeemerald:
ui->checkBox_NewMap_Allow_Running->setVisible(true);
ui->checkBox_NewMap_Allow_Biking->setVisible(true);
ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(true);
ui->spinBox_NewMap_Floor_Number->setVisible(false);
ui->label_NewMap_Allow_Running->setVisible(true);
ui->label_NewMap_Allow_Biking->setVisible(true);
ui->label_NewMap_Allow_Escape_Rope->setVisible(true);
ui->label_NewMap_Floor_Number->setVisible(false);
break;
case BaseGameVersion::pokefirered:
ui->checkBox_NewMap_Allow_Running->setVisible(true);
ui->checkBox_NewMap_Allow_Biking->setVisible(true);
ui->checkBox_NewMap_Allow_Escape_Rope->setVisible(true);
ui->spinBox_NewMap_Floor_Number->setVisible(true);
ui->label_NewMap_Allow_Running->setVisible(true);
ui->label_NewMap_Allow_Biking->setVisible(true);
ui->label_NewMap_Allow_Escape_Rope->setVisible(true);
ui->label_NewMap_Floor_Number->setVisible(true);
break;
}
if (projectConfig.getUseCustomBorderSize()) {
ui->spinBox_NewMap_BorderWidth->setVisible(true);
ui->spinBox_NewMap_BorderHeight->setVisible(true);
ui->label_NewMap_BorderWidth->setVisible(true);
ui->label_NewMap_BorderHeight->setVisible(true);
} else {
ui->spinBox_NewMap_BorderWidth->setVisible(false);
ui->spinBox_NewMap_BorderHeight->setVisible(false);
ui->label_NewMap_BorderWidth->setVisible(false);
ui->label_NewMap_BorderHeight->setVisible(false);
}
}
void NewMapPopup::on_lineEdit_NewMap_Name_textChanged(const QString &text) {
@ -123,11 +150,11 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
newMap->name = newMapName;
newMap->type = this->ui->comboBox_NewMap_Type->currentText();
newMap->location = this->ui->comboBox_NewMap_Location->currentText();
newMap->song = "MUS_DAN02";
newMap->song = this->project->defaultSong;
newMap->requiresFlash = "0";
newMap->weather = "WEATHER_SUNNY";
newMap->weather = this->project->weatherNames->value(0, "WEATHER_NONE");
newMap->show_location = "1";
newMap->battle_scene = "MAP_BATTLE_SCENE_NORMAL";
newMap->battle_scene = this->project->mapBattleScenes->value(0, "MAP_BATTLE_SCENE_NORMAL");
if (this->existingLayout) {
layout = this->project->mapLayouts.value(this->layoutId);
@ -138,6 +165,13 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
layout->name = QString("%1_Layout").arg(newMap->name);
layout->width = QString::number(this->ui->spinBox_NewMap_Width->value());
layout->height = QString::number(this->ui->spinBox_NewMap_Height->value());
if (projectConfig.getUseCustomBorderSize()) {
layout->border_width = QString::number(this->ui->spinBox_NewMap_BorderWidth->value());
layout->border_height = QString::number(this->ui->spinBox_NewMap_BorderHeight->value());
} else {
layout->border_width = QString::number(DEFAULT_BORDER_WIDTH);
layout->border_height = QString::number(DEFAULT_BORDER_HEIGHT);
}
layout->tileset_primary_label = this->ui->comboBox_NewMap_Primary_Tileset->currentText();
layout->tileset_secondary_label = this->ui->comboBox_NewMap_Secondary_Tileset->currentText();
layout->border_path = QString("data/layouts/%1/border.bin").arg(newMapName);
@ -152,6 +186,11 @@ void NewMapPopup::on_pushButton_NewMap_Accept_clicked() {
newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked() ? "1" : "0";
newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked() ? "1" : "0";
newMap->allowEscapeRope = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked() ? "1" : "0";
} else if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
newMap->allowRunning = this->ui->checkBox_NewMap_Allow_Running->isChecked() ? "1" : "0";
newMap->allowBiking = this->ui->checkBox_NewMap_Allow_Biking->isChecked() ? "1" : "0";
newMap->allowEscapeRope = this->ui->checkBox_NewMap_Allow_Escape_Rope->isChecked() ? "1" : "0";
newMap->floorNumber = this->ui->spinBox_NewMap_Floor_Number->value();
}
group = project->groupNames->indexOf(this->ui->comboBox_NewMap_Group->currentText());

View file

@ -5,6 +5,7 @@
#include "metatileparser.h"
#include "paletteutil.h"
#include "imageexport.h"
#include "config.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QDialogButtonBox>
@ -61,6 +62,25 @@ void TilesetEditor::init(Project *project, QString primaryTilesetLabel, QString
this->ui->spinBox_paletteSelector->setMinimum(0);
this->ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1);
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
this->ui->comboBox_encounterType->setVisible(true);
this->ui->label_encounterType->setVisible(true);
this->ui->comboBox_encounterType->addItem("None", 0);
this->ui->comboBox_encounterType->addItem("Land", 1);
this->ui->comboBox_encounterType->addItem("Water", 2);
this->ui->comboBox_terrainType->setVisible(true);
this->ui->label_terrainType->setVisible(true);
this->ui->comboBox_terrainType->addItem("Normal", 0);
this->ui->comboBox_terrainType->addItem("Grass", 1);
this->ui->comboBox_terrainType->addItem("Water", 2);
this->ui->comboBox_terrainType->addItem("Waterfall", 3);
} else {
this->ui->comboBox_encounterType->setVisible(false);
this->ui->label_encounterType->setVisible(false);
this->ui->comboBox_terrainType->setVisible(false);
this->ui->label_terrainType->setVisible(false);
}
//only allow characters valid for a symbol
QRegExp expression("[_A-Za-z0-9]*$");
QRegExpValidator *validator = new QRegExpValidator(expression);
@ -206,6 +226,10 @@ void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) {
this->ui->comboBox_metatileBehaviors->setCurrentIndex(this->ui->comboBox_metatileBehaviors->findData(this->metatile->behavior));
this->ui->lineEdit_metatileLabel->setText(this->metatile->label);
this->ui->comboBox_layerType->setCurrentIndex(this->ui->comboBox_layerType->findData(this->metatile->layerType));
if (projectConfig.getBaseGameVersion() == BaseGameVersion::pokefirered) {
this->ui->comboBox_encounterType->setCurrentIndex(this->ui->comboBox_encounterType->findData(this->metatile->encounterType));
this->ui->comboBox_terrainType->setCurrentIndex(this->ui->comboBox_terrainType->findData(this->metatile->terrainType));
}
}
void TilesetEditor::onHoveredTileChanged(uint16_t tile) {
@ -355,6 +379,26 @@ void TilesetEditor::on_comboBox_layerType_activated(int layerType)
}
}
void TilesetEditor::on_comboBox_encounterType_activated(int encounterType)
{
if (this->metatile) {
Metatile *prevMetatile = this->metatile->copy();
this->metatile->encounterType = static_cast<uint8_t>(encounterType);
MetatileHistoryItem *commit = new MetatileHistoryItem(metatileSelector->getSelectedMetatile(), prevMetatile, this->metatile->copy());
metatileHistory.push(commit);
}
}
void TilesetEditor::on_comboBox_terrainType_activated(int terrainType)
{
if (this->metatile) {
Metatile *prevMetatile = this->metatile->copy();
this->metatile->terrainType = static_cast<uint8_t>(terrainType);
MetatileHistoryItem *commit = new MetatileHistoryItem(metatileSelector->getSelectedMetatile(), prevMetatile, this->metatile->copy());
metatileHistory.push(commit);
}
}
void TilesetEditor::on_actionSave_Tileset_triggered()
{
saveMetatileLabel();
@ -559,6 +603,8 @@ void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
Metatile *metatile = new Metatile;
metatile->behavior = 0;
metatile->layerType = 0;
metatile->encounterType = 0;
metatile->terrainType = 0;
for (int i = 0; i < 8; i++) {
metatile->tiles->append(tile);
}
@ -577,6 +623,8 @@ void TilesetEditor::on_actionChange_Metatiles_Count_triggered()
Metatile *metatile = new Metatile;
metatile->behavior = 0;
metatile->layerType = 0;
metatile->encounterType = 0;
metatile->terrainType = 0;
for (int i = 0; i < 8; i++) {
metatile->tiles->append(tile);
}