Coder Social home page Coder Social logo

easyrpg / editor Goto Github PK

View Code? Open in Web Editor NEW
332.0 29.0 56.0 8.13 MB

Game editor similar to RPG Maker

Home Page: https://easyrpg.org/editor/

License: GNU General Public License v3.0

C++ 96.59% CMake 2.81% C 0.60%
rpg-maker game-editor rpg-maker-2003 rpg-maker-2000

editor's People

Contributors

carstene1ns avatar fdelapena avatar fmatthew5876 avatar ghabry avatar half-time-demon avatar hellow554 avatar lobomon avatar marianognu avatar molasseslover avatar ravotd avatar rohkea avatar tyrone-sudeium avatar wjk avatar zegeri avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

editor's Issues

Don't rely on QPixmap to figure out extension but probe manually for png/bmp[/xyz]

The current editor code relies on an undocumented QPixmap feature for loading the graphics:

It requests QPixmap to load e.g. ChipSet/Basis and then QPixmap tries to open (in this order according to strace):
Basis, Basis.bmp, Basis.cur, Basis.gif, Basic.ico, Basic.jpeg, Basis.jpg, Basis.pbm, Basis.pgm, Basis.png

Imo this is bad style because it loads file formats the Player does not support and bmp is prefered over png ๐Ÿ‘Ž

I have no idea why this is even happening the documentation says:
"Constructs a pixmap from the file with the given fileName. If the file does not exist or is of an unknown format, the pixmap becomes a null pixmap. The loader attempts to read the pixmap using the specified format. If the format is not specified (which is the default), the loader probes the file for a header to guess the file format."

It only states "the loader probes for a header", not "the loader probes by appending all supported image extensions".

RPG Maker Custom Ui to implement

Here all custom Ui that is in the editor that can't be implemented by normal Qt Widgets.
Good to collect this, then the files can be stubbed by a code-generator, so they are already there and "only" the implementation is missing.

Terminology:

  • The representation on the database tabs is the Viewer (Base QGraphicsScene), when double clicking it you usually get an Editor or a Picker.
  • A Picker has two panes: A File Select on the left, a custom Widget on the right
  • A Editor is anything else where no file select is involved

List of Pickers:

  • CharSetPicker. Right pane: Select one out of 8 CharSets
  • EventCharSetPicker. As above but supports TileMap select and CharSet Direction Pattern picking
  • FaceSetPicker: Right pane: Select one out of 16 Faces
  • SoundEffectPicker: Right pane: SE config stuff
  • MusicPicker: Right pane: Music config stuff
  • EnemyPicker: Right pane: Hue select
  • BackdropPicker
  • ChipsetPicker
  • TitlePicker
  • GameOverPicker
  • PanoramaPicker
  • SystemPicker: Right Pane: Font select and stretch/tile
  • BattleAnimation2Picker
  • FramePicker
  • System2Picker

List of Editors:

  • ParameterCurveEditor
  • ExperienceCurveEditor

Actor:

  • FaceSetViewer. Shows one face. Opens a FaceSetPicker
  • CharSetViewer. Shows one animate CharSet. Opens a CharSetPicker
  • ParameterCurveViewer opens a ParameterCurveEditor
  • ExperienceCurveViewer opens a ExperienceCurveEditor

Skill/Item:

  • BattleAnimationViewer. Plays one Battle Animation. Opens a BattleAnimationPicker

Enemy:

  • EnemyViewer. Opens a EnemyPicker
  • EnemyActionWidget: Select condition and action for enemy

Troop:

  • TroopViewer: This is also an editor. You can put enemies on the battle field
  • BattleEventConditionWidget: Select event start conditions

State:

  • SystemComboBox Nice to have. Shows the system colors in a combobox.

Animation:

  • AnimationViewer: This is also an editor. You can put animations here.
  • TODO: Extra widget 1 for Animation config
  • TODO: Extra widget 2 for Animation config

Animation 2:

  • BattleAnimation2Viewer. Opens a BattleAnimation2Picker

BattleScreen:

  • Can't be configured but there is some battle preview thing

Terrain:

  • BackdropViewer: Opens a BackdropPicker
  • Rpg2k3: TerrainViewer (Note: The terrain can be directly edited)

Tileset:

  • TilesetTerrainEditor: Inline widget. Supports lower/upper layer passability config stuff
  • TileViewer: Shows a tile. Supports animated water autotiles.

System:

  • TitleViewer. Opens a TitlePicker
  • GameOverViewer. Opens a GameOverPicker
  • SystemViewer. Opens a SystemPicker
  • SoundEffectComboBox. Opens a SoundEffectPicker #165
  • MusicComboBox. Opens a MusicPicker #165

System2:

  • FrameViewer: Opens a FramePicker
  • System2Viewer: Opens a System2Picker

Events:
There are no real extra components here except for:

  • MapLocationPicker: Shows a maptree and a map (and optional direction) for Location picking

CBA crap: The last to implement because we hate this the most in Player :P

  • TODO: Widget 1
  • TODO: Widget 2

Design API for "complex" event commands

From an editor point of view there are two types of event commands:

Basic event commands: The event only operates on there data (Currently the API only supports this)

There are two types of complex commands:

E.g. Message Command & Comment

  • The commands following the main command are lines belonging to it

E.g. Branches

  • They can add/delete if/else branches directly after the command

Incorrect AutoTile IDs

When importing a game from RPG Maker 2000 deep water corners looks incorrectly.
When importing a game from RPG Maker 2003 some deep water corners tiles are not detected by Editor and not rendered at all.

Both cases must be checked in theirs counter-versions.

image

Modules

Hello, I am working on a module system to allow the editors to be extendable with library loading (think dll or so) along with some form of XML (for small modules that don't need C/C++ cababillities). If you have any requests I would be happy to hear. Currently I have just finished getting things set up, but have studied the source code. Also I have never used issues before so please don't judge too hard.

Renaming and moving data

If you want to move stuff around such as items, skills, variables, etc.. in RPG Maker you have a big problem. If I want to change "Long Sword" from item id 100 to id 120, I have to somehow update all references to the old item id in event code and fix it. Renaming resource files is also a huge pain and can result in crashes in RPG_RT.

The editor should have an easy to use and intuitive way to support reorganizing data. Almost like a refactoring tool in an IDE.

Possibly uninitialized data shows tile garbage on editor map canvas

Looks like when using zero initialized vars works fine on MSVC (default for debug build), however importing RPG Maker 2000/3 maps from Editor build with gcc generates visual garbage in the editor canvas.

This also only happens when the reference tileset is not found. It should paint the tile black instead.

As a side note, the file finder is not case insensitive and fails to load files in case sensitive file systems. The RTP path does not provide a RTP alternative table for imported games, so having the filefinder into liblcf may help with this (EasyRPG/liblcf#137).

Create a new map issue

Hi,
macOS Big Sur User here. I can open a rm2k Project but if I want to add a new map I get this message:
The file /private/var/folders/4w/qt32_g8s5ms21nybw0ldrr240000gn/T/AppTranslocation/7167517A-615C-451C-8262-AE684F329C6C/d/EasyRPG Editor.app/Contents/MacOS/templates/Map0001.emu can't be found.

if I click OK I can edit again but there is no new map.

The build date is 21.09.2020 - A release from Ghabry =)

Nested directory and window modality problems in MainWindow::ImportProject

MainWindow::ImportProject uses recurseAddDir to enumerate files in the resource directories. In theory this should handle subdirectories in the resource directories, but the implementation does not work properly. This creates problems importing certain RPM2K games that do this.

The error dialog that is displayed is modal, with a parent of this, which in turn calls exec that runs the event pump to display the modal QProgressDialog which will be the active modal window. This makes closing the error dialog confusing.

The patch below resolves both issues, the former by handling recurseAddDir paths as relative to the provided base rather than as absolute paths. This allows for clean composition of source and destination paths. Furthermore, it makes the error dialog parent widget the qprogressdialog, which is now explicitly shown before the error dialog is created. This makes the modal hierarchy clear and function intuitively.

diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 0af3693..c7c3c74 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -36,26 +36,23 @@ const std::vector<QString> resource_dirs =
     {BACKDROP, BATTLE, BATTLE2, BATTLECHARSET, BATTLEWEAPON, CHARSET, CHIPSET, FACESET,
     GAMEOVER, MONSTER, MOVIE, MUSIC, PANORAMA, PICTURE, SOUND, SYSTEM, SYSTEM2, TITLE};
 
-static void recurseAddDir(QDir d, QStringList & list) {
-
-    QStringList qsl = d.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);
+static void recurseAddDir(const QString &basedir, QStringList &list, const QString &curdir = QString())
+{
+    QDir cur(basedir + curdir);
+    QStringList qsl = cur.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);
 
     foreach (QString file, qsl) {
-
-        QFileInfo finfo(QString("%1/%2").arg(d.path()).arg(file));
+        QString   path_absolute = cur.filePath(file);
+        QString   path_relative = QDir(curdir).filePath(file);
+        QFileInfo finfo(path_absolute);
 
         if (finfo.isSymLink())
             return;
 
-        if (finfo.isDir()) {
-
-            QString dirname = finfo.fileName();
-            QDir sd(finfo.filePath());
-
-            recurseAddDir(sd, list);
-
-        } else
-            list << QDir::toNativeSeparators(finfo.filePath());
+        if (finfo.isDir())
+            recurseAddDir(basedir, list, path_relative);
+        else
+            list << path_relative;
     }
 }
 
@@ -290,42 +287,43 @@ void MainWindow::ImportProject(QString p_path, QString d_folder, bool convert_xy
     LDB_Reader::SaveXml(mCore->filePath(ROOT, EASY_DB).toStdString());
     LMT_Reader::SaveXml(mCore->filePath(ROOT, EASY_MT).toStdString());
     QStringList entries;
+
     for (const QString& dir : resource_dirs)
-        recurseAddDir(QDir(p_path+dir), entries);
+        recurseAddDir(p_path, entries, dir);
 
     QProgressDialog progress("Importing resources...", "", 0, entries.count(), this);
     progress.setWindowModality(Qt::WindowModal);
+    progress.setFixedSize(progress.size());
+    progress.show();
+
     for (int i = 0; i < entries.count(); i++)
     {
+        QString dest_file = mCore->filePath(entries[i]);
+        QString src_file  = p_path + entries[i];
+
         progress.setValue(i);
-        QFileInfo info(entries[i]);
-        QString dest_file = mCore->filePath(info.dir().dirName()+"/",info.fileName());
-        if (!QFile::copy(entries[i], dest_file))
+
+        if (!QDir::root().mkpath(QFileInfo(dest_file).path()) ||
+            !QFile::copy(src_file, dest_file))
         {
-            QMessageBox box(this);
             QString name = tr("Error");
             QString text = tr("Could not copy file %1 to \n"
-                              "%2").arg(entries[i]).arg(dest_file);
-
-            box.setModal(true);
-            box.setWindowTitle(name);
-            box.setText(QString::fromLatin1("%1").arg(text));
-            box.setIcon(QMessageBox::Critical);
-            box.setStandardButtons(QMessageBox::Ok);
-
-            box.exec();
-
+                              "%2").arg(QDir::toNativeSeparators(src_file))
+                                   .arg(QDir::toNativeSeparators(dest_file));
+            QMessageBox::critical(&progress, name, text);
             on_action_Close_Project_triggered();
             return;
         }
-        if (convert_xyz && info.dir().dirName() != MUSIC && info.dir().dirName() != SOUND)
+
+        if (convert_xyz && !entries[i].startsWith(MUSIC) && !entries[i].startsWith(SOUND))
         {
             QFile file(dest_file);
             file.open(QIODevice::ReadOnly);
             if (file.read(4) == "XYZ1")
             {
-                QString conv_path = mCore->filePath(info.dir().dirName()+"/",
-                                                    info.completeBaseName() + ".png");
+                QFileInfo fi(entries[i]);
+                QString conv_path = mCore->filePath(fi.path() + "/" + fi.completeBaseName() + ".png");
+               // XXX: should handle .png that already exists (both .xyz and .png file in src)
                 if (convertXYZtoPNG(file, conv_path))
                     file.remove();
                 else

Move Database Tabs to the Left

This (extremely obvious) idea is kinda stolen from RPG Maker MV but we should do it to reduce horizontal scrolling.

Also is not essential to use tabs here, can be also a List.

Project Folder Structure & Naming

We are basicly just starting development again, so lets finish the organisational part :D

Some files don't use CamelCase and are completely lower, e.g.
dialogfacepicker

Many classes are prefixed with Q for no real reason, imo the Q can be removed.

Put license on top of all source files

There could be also some logical grouping in folders. Most for the UI files, no idea, something like:

  • database
  • events (this is currently commands)
  • map (all dialogs related to the map and the map tree)
  • common (for commonly used stuff like Switch/Variable picker)
  • [drop everything else in the src root for now]

Only with database and events in sub folders this would reduce the clutter in the src directory alot.

Handle Skill::sp_percent correctly

This field defaults to 0. When in the rm2k3 editor, you select the radio button to choose percent for the first time it immediately changes to 1 and can never be set to 0 again.

We don't necessarily have to do it this way, but having both sp_type == percent && sp_percent == 0 is not a valid state.

Mentioning this as its a bit of an edge case to not forget.

Support tags/sections for maps tree

Actually making a game with many maps needs organization, the only way to separate maps is using dummy maps.

Create new maps and call them "Towns", "Dungeon", etc
Unused maps...

So for example, a tree map looks like:

001-Towns
----------Town 01
----------Town 02

002-Dungeons
-----------Dungeon 01

003-Sequence maps
-------------Intro

(A big project needs organization more or less)

Supporting sections you don't need empty maps to use many of them as organization.
Tags idea can be used as
"Completed", "Need Revision", "Debug only", etc
Good after check a project if you forget something (without write a lot of documentation on a calc file or something)

Maybe without need to add this to the lmu file, or map tree.

Database Window opens with wrong size

Hi,

if I open the Database window, the Window is to small and some controls overlap like this:

image

If I resize the window for only 1px the window "jumps" to the right size and the controls are on the right place.

a question

why I can't find the file which name is " rpg_map.h" and "data.h"

Textual event script writing and compiling

Clicking around boxes for event code is nice for newbies, but it's horribly slow if you know what you're doing.

I would really want some kind of way to type event script on the keyboard.

This is a somewhat big project. We would need to define the text syntax for each command, and write a parser / compiler for it. It would also be nice if game projects could leave the event script files as text and compile them into lcf binary for shipping.

No other scripting language really fits, so this would likely end up being a custom scripting language of sorts. Essentially something declarative which just executes commands.

So all of this might end up being part of liblcf.

Undefined symbols when linking with liblcf on OSX

I am trying to compile Editor on OS X 10.9. It compiles, but the linker fails, claiming that a number of symbols from liblcf.a are not found. No matter what I try, it still refuses to find liblcf. What can I do?

Always include numbers in lists of RPG elements

The many drop down boxes in RPG Maker Editor for things like common events, animations, items, etc.. are super painful to navigate.

One thing that would really help is to include the number.

Like instead of Long Sword you'd have 0018: Long Sword everywhere.

I would also include numbers in the treemap view for Maps. Its not easily matching up map id's to map names in RPG Maker Editor.

Chunk View / Edit tool

We need a chunk editing tool.

This is very minimal application which loads a single LDB, LMT, LMU, or LSD file. It would only let you view chunks, and write chunks.

It would display the chunks of the file in a single tree view widget. The entire treeview code would be pretty simple to generate from liblcf csv files in python.

I put it here as this makes sense as a standalone simple Qt application. It could also be ncurses, or both.

This would be very useful for gamedevs as a low level tool to test out new functionality and perform game debugging.

This would also be great for EasyRPG to debug problems. Because of all of the size counters, its not convenient to directly edit files in a hex editor like Beyond Compare. Something that had knowledge of chunk structure could.

The UI for this could also be reused to build a frame by frame recording of LSD data and do event tracing.

This should be pretty simple to implement, since there will only be one main widget.

RFC: Project structure

Currently we simply convert the LDB & co. to XML and rename it to .edb & co.
This needs a solution before the editor is released to the public imo because when the first people start using it, it is too late.

Imho this could be heavily improved by splitting everything in small XML (or JSON?) files.

Though we don't want to copy from MV so I suggest something different. We split it even more:

easyrpg.project <-- Project info file
data/
|- actors/
|--- 1.xml
|--- 2.xml
|--- [...] all actors
|- common_events
|-- 1.xml
|-- 1.script
|-- 2.xml
|-- 2.script
|-- [...]
|- [...]/
|- terms.xml
|- system.xml
|- assets/
|-- CharSet
|-- ChipSet
|-- [...] everything you know
|- maps/
|-- tree.xml <-- map tree
|-- 1/ <-- Map ID
|--- map.xml <-- Describes map structure (tiles)
|--- index.xml <-- autogenerated file with event properties and start conditions
|--- 1.xml <-- Event with ID 1
|--- 1-1.script <-- Script page 1 of event 1
|--- 1-2.script 
|--- 2.xml
|--- [...]
|--- 500.xml

Cons:

  • Lots of files, making operations on lots of files really slow
  • Needs an (automatic generated) index at least for events because the interpreter must know which start conditions are met without parsing all files
  • File system overhead (cluster size) but could be worked around by supporting zip or by merging everything together for deployment

Pros:

  • Editing specific data with a text editor (or an automated script) gets easier
  • Sharing single data points (e.g. 1 actor) and adding them to a different project becomes super easy
  • Better colloborative editing in a repository because merge conflicts are getting less
  • script is in an extra file to support a more sane scripting language later
  • liblcf could abstract most of this away by adding getters/setters which automatically parse these files on access

So this is in general stuff that is only relevant for the power user and for revision control.

You can vote ๐Ÿ‘Ž now ;)

Roadmap for 0.1

Main Window:

  • Open project.
  • Create new project.
  • Close project.
  • Import project.
  • Create new map.
  • Edit map properties.
  • Copy/paste maps.
  • Delete maps.
  • Open maps in independent tabs.
  • Launch Game.
  • launch game in a specific position (skips title scene).

Map View:

  • Render Maps.
  • Render Autotiles correctly.
  • Edit upper and lower layers using a pen tool.
  • Edit upper and lower layers using a rectangle tool.
  • Edit upper and lower layers using a circle tool.
  • Edit upper and lower layers using a fill tool.
  • Undo last draw.

Events

  • Show map's event edition window.
  • Edit event's page initial conditions and options.
  • list event commands in a tree widget.
  • Verbalize event commands. (53/123).
  • Edit event commands.
  • Add new event commands.
  • Add new event pages.
  • Copy/paste event pages.
  • Delete event pages.
  • Undo last event edition.

Database

  • Show data in oldSchool tabs (2/17).
  • Show data in newStyle tables (0/17).
  • Save changes when clicking Apply or Ok buttons.
  • Split edition tabs in independent widgets.

Actors

  • Fill Actors List.
  • Display selected actor's data.
  • Render evolution curves.
  • Render actor's Face, CharaSet and Battler.
  • Modify string values (2/2)
  • Modify numeric values (10/10)
  • Modify check values (5/5)
  • Modify evolution curves.
  • Modify experience curve.
  • Modify skill learning table.
  • Modify Attribute/States rank asociation.
  • Set parametters when Apply Profession button is pressed.

Professions

  • Fill Professions List.
  • Display selected profession's data.
  • Render Profession's Battler and curves.

Vocabulary

  • Display data.
  • Modify data.

14 Remaning Tabs.

  • Fill data.
  • Modify data.

Include libs with a git submodule

It's possible to add other gits in a git, just do:

git submodule add https://github.com/EasyRPG/liblcf.git libs/liblcf

in the root folder.
Anyone who wants to use your repository will have to type the following commands:

git submodule init
git submodule update

I hope this help

Get rid of global state

We learned from Player that the worst you can have is global state ;). In editor calling across object boundaries doesn't happen very often, there are not thousands of interactions between each other as in a game engine.

In Editor the parent object is the Core. This is a global singleton entrypoint.
The Core owns a Project which is the currently loaded project.
Outside of the MainWindow I want to discourage any access to this global (and make it private later).

Maybe later we want to have two projects loaded at once, getting rid of accessing global data is great to make this easy to implement.
I already considered this by forwarding the lcf::rpg::Database everywhere instead of doing core()->project()->database.
Forwarding project is also fine e.g. when File Finder access is required.

Current places with core-access left:

  • Worst offender is map_scene with 110 calls (but this one has refactor pending anyway).
  • Main window does 91: This is fine, main window is at the bottom of the hierarchy.

With these removed there are 147 calls left (with map_properties and stringizer removed only 71 left):

src/core.cpp
113:    for (unsigned int i = 0; i < core().project()->database().chipsets.size();i++)
114:            if (core().project()->database().chipsets[i].ID == n_chipsetid)
116:                    m_chipset = core().project()->database().chipsets[i];

src/ui/event/event_page_widget.cpp
120:    if (switchId >= 1 && switchId <= static_cast<int>(core().project()->database().switches.size())) {
123:                                     (core().project()->database().switches[static_cast<size_t>(switchId) - 1].name));
164:            if (varId >= 1 && varId <= static_cast<int>(core().project()->database().variables.size())) {
167:                                     (core().project()->database().variables[static_cast<size_t>(varId) - 1].name)));
337:            core().beginPainting(pix);
338:            core().renderTile(10000 + static_cast<short>(m_eventPage->character_index), QRect(0,0,16,16));
339:            core().endPainting();

src/ui/other/search_dialog.cpp
63:     for (auto &v : core().project()->database().variables)
65:     for (auto &s : core().project()->database().switches)
67:     for (auto &i : core().project()->database().items)
69:     for (auto &e : core().project()->database().commonevents)
78:             map_cache = std::vector<std::shared_ptr<lcf::rpg::Map>>(core().project()->treeMap().maps.size());
244:            showResults(common_searcher(core().project()->database().commonevents));
248:            for (auto &map : core().project()->treeMap().maps)
250:                    ui->label_status->setText(QString("Parsing Map %1 / %2").arg(QString::number(map.ID + 1), QString::number(core().project()->treeMap().maps.size())));
277:            const std::shared_ptr<lcf::rpg::Map> res_map{core().project()->loadMap(mapID)};
305:                            auto& mapinfo = core().project()->treeMap().maps[static_cast<size_t>(mm)];

src/ui/other/rtp_path_dialog.cpp
29:     ui->lineRtpPath->setText(core().rtpPath(""));
51:     core().setRtpDir(ui->lineRtpPath->text());

src/ui/other/run_game_dialog.cpp
97:     for (size_t i = 1; i < core().project()->treeMap().maps.size(); i++)
99:             if (core().project()->treeMap().maps[i].type == 1)
101:                    ui->comboMapId->addItem(ToQString(core().project()->treeMap().maps[i].name),
102:                                                                    core().project()->treeMap().maps[i].ID);
109:    for (size_t i = 1; i < core().project()->database().troops.size(); i++)
110:            ui->comboTroop->addItem(ToQString(core().project()->database().troops[i].name));
112:    bool auto_placement = static_cast<bool>(core().project()->database().battlecommands.placement);
122:    for (size_t i = 0; i < core().project()->database().terrains.size(); i++)
123:            ui->comboCustomFormation->addItem(ToQString(core().project()->database().terrains[i].name));
125:    battletest_data = core().project()->database().system.battletest_data;

src/ui/database/actor_delegate.cpp
34:     for (size_t i = 0; i < core().project()->database().actors.size(); i++)
35:             editor->addItem(ToQString(core().project()->database().actors[i].name), core().project()->database().actors[i].ID);
49:     model->setData(index, ToQString(core().project()->database().actors[static_cast<size_t>(id)-1].name));

src/ui/database/database_dialog.cpp
30:     m_data(core().project()->database())
80:     for (unsigned int i = 0; i < core().project()->database().actors.size(); i++)
83:                                                                .arg(core().project()->database().actors[i].name.c_str()));
176:                    core().project()->saveDatabase();

src/ui/common/faceset_picker_dialog.cpp
31:     QDir dir(core().project()->findFile(FACESET));
45:     dir = QDir(core().rtpPath(FACESET));

src/ui/common/charset_picker_dialog.cpp
40:             core().beginPainting(pix);
42:                     core().renderTile(10000+i, QRect((i%6)*16,i/6*16,16,16));
43:             core().endPainting();
51:     QDir dir(core().project()->findFile(CHARSET));
65:     dir = QDir(core().rtpPath(CHARSET));

src/ui/common/encounter_delegate.cpp
34:     for (size_t i = 0; i < core().project()->database().troops.size(); i++)
35:             editor->addItem(ToQString(core().project()->database().troops[i].name));
49:     model->setData(index, ToQString(core().project()->database().troops[static_cast<size_t>(id)-1].name));

src/ui/common/palette_scene.cpp
47:     if (core().layer() == Core::LOWER)
57:     m_tiles->graphicsEffect()->setEnabled(core().layer() != Core::LOWER);
62:     if (core().chipsetIsNull())
80:     core().beginPainting(m_lowerTiles);
84:             core().renderTile(core().translate(terrain_id,15), rect);
86:     core().renderTile(core().translate(2,0,240), QRect(64,32,32,32));
87:     core().endPainting();
88:     core().beginPainting(m_upperTiles);
92:             core().renderTile(core().translate(terrain_id+162), rect);
94:     core().endPainting();
180:            core().setSelection(sel, 1, 1);
187:                            if (core().layer() == Core::LOWER)
188:                                    sel.push_back(core().translate(_x+_y*6, SAMPLE));
190:                                    sel.push_back(core().translate(_x+_y*6+162, SAMPLE));
191:            core().setSelection(sel, w, h);

src/ui/common/faceset_item.cpp
30:     m_pix = ImageLoader::Load(core().project()->findFile(FACESET, n_pixName, FileFinder::FileType::Image));
32:             m_pix = QPixmap(core().rtpPath(FACESET,n_pixName));

src/ui/common/charset_item.cpp
35:     m_pix = ImageLoader::Load(core().project()->findFile(CHARSET, n_pixName, FileFinder::FileType::Image));
37:             m_pix = ImageLoader::Load(core().rtpPath(CHARSET, n_pixName));
39:             m_pix = core().createDummyPixmap(288,256);

src/ui/common/battle_animation_item.cpp
55:             m_pix = QPixmap(core().project()->findFile(dir, pixName, FileFinder::FileType::Image));
57:                     m_pix = QPixmap(core().rtpPath(dir, pixName));

src/ui/maptree/map_properties_dialog.cpp
33:             m_generatorLowerLayer.push_back(core().translate(terrain, UP+DOWN+LEFT+RIGHT));
51:     for (int i = 0; i < static_cast<int>(core().project()->database().chipsets.size()); i++)
52:             ui->comboTileset->addItem(ToQString(core().project()->database().chipsets[static_cast<size_t>(i)].name), i+1);
93:             item->setData(Qt::DisplayRole, ToQString(core().project()->database().troops[static_cast<size_t>(info.encounters[static_cast<size_t>(i)].troop_id)-1].name));
127:    core().beginPainting(pix);
128:    core().renderTile(map.generator_tile_ids[0], QRect(0,0,32,32));
129:    core().endPainting();
133:    core().beginPainting(pix);
134:    core().renderTile(map.generator_tile_ids[1], QRect(0,0,32,32));
135:    core().endPainting();
139:    core().beginPainting(pix);
140:    core().renderTile(map.generator_tile_ids[2], QRect(0,0,32,32));
141:    core().endPainting();
145:    core().beginPainting(pix);
146:    core().renderTile(map.generator_tile_ids[3], QRect(0,0,32,32));
147:    core().endPainting();
151:    core().beginPainting(pix);
152:    core().renderTile(map.generator_tile_ids[4], QRect(0,0,32,32));
153:    core().endPainting();
157:    core().beginPainting(pix);
158:    core().renderTile(map.generator_tile_ids[5], QRect(0,0,32,32));
159:    core().endPainting();
164:    core().beginPainting(pix);
165:    core().renderTile(map.generator_tile_ids[6], QRect(0,0,32,32));
166:    core().renderTile(map.generator_tile_ids[7], QRect(32,0,32,32));
167:    core().renderTile(map.generator_tile_ids[8], QRect(0,32,32,32));
168:    core().renderTile(map.generator_tile_ids[9], QRect(32,32,32,32));
169:    core().endPainting();
173:    core().beginPainting(pix);
174:    core().renderTile(map.generator_tile_ids[10], QRect(0,0,32,32));
175:    core().renderTile(map.generator_tile_ids[11], QRect(32,0,32,32));
176:    core().renderTile(map.generator_tile_ids[12], QRect(0,32,32,32));
177:    core().renderTile(map.generator_tile_ids[13], QRect(32,32,32,32));
178:    core().endPainting();
182:    core().beginPainting(pix);
183:    core().renderTile(map.generator_tile_ids[14], QRect(0,0,32,32));
184:    core().renderTile(map.generator_tile_ids[15], QRect(32,0,32,32));
185:    core().renderTile(map.generator_tile_ids[16], QRect(0,32,32,32));
186:    core().renderTile(map.generator_tile_ids[17], QRect(32,32,32,32));
187:    core().endPainting();
192:            pix = QPixmap(core().project()->findFile(PANORAMA, ToQString(map.parallax_name), FileFinder::FileType::Image));
194:                    pix = QPixmap(core().rtpPath(PANORAMA,ToQString(map.parallax_name)));

src/stringizer.cpp
1216:           if (id < 1 || id > static_cast<int>(core().project()->database().variables.size()))
1218:           return ToQString(core().project()->database().variables[static_cast<size_t>(id)-1].name);
1223:           if (id < 1 || id > static_cast<int>(core().project()->database().switches.size()))
1225:           return ToQString(core().project()->database().switches[static_cast<size_t>(id) - 1].name);
1230:           if (id < 1 || id > static_cast<int>(core().project()->database().items.size()))
1232:           return ToQString(core().project()->database().items[static_cast<size_t>(id)-1].name);
1237:           if (id < 1 || id > static_cast<int>(core().project()->database().actors.size()))
1239:           return ToQString(core().project()->database().actors[static_cast<size_t>(id)-1].name);
1244:           if (id < 1 || id > static_cast<int>(core().project()->database().classes.size()))
1246:           return ToQString(core().project()->database().classes[static_cast<size_t>(id)-1].name);
1251:           if (id < 1 || id > static_cast<int>(core().project()->database().states.size()))
1253:           return ToQString(core().project()->database().states[static_cast<size_t>(id)-1].name);
1258:           if (id < 1 || id > static_cast<int>(core().project()->database().skills.size()))
1260:           return ToQString(core().project()->database().skills[static_cast<size_t>(id)-1].name);
1265:           if (id < 1 || id > static_cast<int>(core().project()->database().battlecommands.commands.size()))
1267:           return ToQString(core().project()->database().battlecommands.commands[static_cast<size_t>(id)-1].name);
1273:           if (id < 1 || id > static_cast<int>(core().project()->database().animations.size()))
1275:           return ToQString(core().project()->database().animations[static_cast<size_t>(id)-1].name);
1279:           if (id < 1 || id > static_cast<int>(core().project()->database().states.size()))
1281:           return ToQString(core().project()->database().states[static_cast<size_t>(id)-1].name);
1286:           if (!core().currentMapEvent(id))
1288:           return ToQString(core().currentMapEvent(id)->name);
1293:           if (id < 1 || id > static_cast<int>(core().project()->database().commonevents.size()))
1295:           return ToQString(core().project()->database().commonevents[static_cast<size_t>(id)-1].name);
1300:           if (id < 1 || id > static_cast<int>(core().project()->database().troops.size()))
1302:           return ToQString(core().project()->database().troops[static_cast<size_t>(id)-1].name);
1307:           if (id < 1 || id > static_cast<int>(core().project()->database().terrains.size()))
1309:           return ToQString(core().project()->database().terrains[static_cast<size_t>(id)-1].name);
1314:           if (id < 1 || id > static_cast<int>(core().project()->treeMap().maps.size()))
1316:           for (unsigned i = 0; i < core().project()->treeMap().maps.size(); i++)
1317:                   if (core().project()->treeMap().maps[i].ID == id)
1318:                           return ToQString(core().project()->treeMap().maps[i].name);

src/model/enemy.cpp
32:     QPixmap monster = ImageLoader::Load(core().project()->findFile("Monster", ToQString(data().battler_name), FileFinder::FileType::Image));

src/model/actor.cpp
34:     QPixmap faceSet = ImageLoader::Load(core().project()->findFile("FaceSet", ToQString(actor.face_name), FileFinder::FileType::Image));

Clipboard interoperability with RPG Maker Editor

For everything makes no sense imo (lots of work) but for Script copy-paste there could be use-cases.
Also makes japanese tools and Cherrys Evt Tools usable.

Need to figure out the format first, shouldn't be too difficult with a clipboard viewer.

Bonus points when copy-paste from/to editor in Wine works.

Maybe @CherryDT knows if there is a public doc on this somewhere. Only for event commands.

Positioning pictures visually

There's a tool for 2k, 2k3, XP and VX called "Img positioner".

imgp

You can adjust the XY values, as it has always been done in RPG Maker, or move the image directly with the cursor and the values are recalculated.
Basically it'd be to absorb the same idea for the "Show Picture" section of the editor.

ImagePositioner_esp.zip

Question - End?

Hello,

The development of this program is still active?
Thanks a lot!

Apply Massive Changes

I know that @Ghabry has already seen it, but I think it is interesting that this feature has been noted.

I made a mockup, but very possibly that feature should be separated (maybe at the top, when an event is opened, where the event pages are)

massive-changes

Basically the idea is that batch changes can be applied in the next X lines for that type of command. For example, in the mockup it would be applied on the show/move picture. So perhaps it is better to separate the function where the user chooses which command or commands will apply the batch changes.

In the approach of the screenshot, the value 0 will only apply it on the current line, but it depends on the editor being intelligent, not being able to enter a greater number than the number of lines in use so far.

Selecting "All" will apply to all such lines at the event.

There I leave the idea to see what is the best approach to integrate an improvement that would save time updating data that so far are made one by one and sometimes are many lines.

Thanks.

typo in code

file dialogsearch.cpp, line 132

                case Cmd::RecallToLocation:
                    return com.parameters[0] == varID || com.parameters[1] == varID ||
                        **com.parameters[1] == varID;**

double com.parameters[1] == varID

Could NOT find liblcf (missing: LIBLCF_LIBRARY LIBLCF_INCLUDE_DIR) (found version "0.5.4")

Could NOT find liblcf (missing: LIBLCF_LIBRARY LIBLCF_INCLUDE_DIR) (found
  version "0.5.4")
Call Stack (most recent call first):
  /usr/local/Cellar/cmake/3.12.2/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:378 (_FPHSA_FAILURE_MESSAGE)
  /Users/lmenezes/Cloned_From_Github/easyRPG/liblcf/builds/liblcf-config.cmake:57 (find_package_handle_standard_args)
  CMakeLists.txt:146 (find_package)

Copy&Paste a Map does not work

Hi,

I can't copy and paste a map. If I try to copy a map the paste icon is enabled. But If I try to paste a map I get the following message:

image

Whitespace standard?

liblcf and Player use tabs. Editor uses spaces as thats the default setting in QtCreator.

I like spaces personally, but not enough to really care. Shouldn't all of the projects use the same standard?

Changing all of editor to tabs would be easier at this time since its currently not being as actively developed as Player and liblcf.

Extend Editor with official plugins

Maybe a series of commands could be in the editor (all the ones from RPG Maker, maybe some of certain plugins, like some of the commands from Maniacs Patch).

Extending the functionality of the editor would depend on what the user requires and could be extended with plugins, I leave a little bit shabby mockup so that it can be better understood.

imagen

Update actors initial equipment when item is edited

Another edge case to remember. RPG Maker Editor is smart enough to refresh actor equipment.

For example if you change a weapon to 2 handed, actors weapons will update and anyone with dual weapons will get the other removed.

RFC: Editor-Player-IPC

By fmatthew:

There's a few use cases I see really

  • Reusing player logic for complicated things like tile mapping - Refactor out globals, just call functions or create / destroy isolated class instances directly in editor.

For this, what we can and should do is isolate the interfaces we want to reuse from global state using dependency injection. This also helps with making Player itself unit testable. More refactors like the Algo library for this.

  • Actually running player game engine embedded in Qt and somehow allowing live editing and debugging - Requires engine globals

To be able to start and stop player within editor itself, yes I agree we need a very clean creation and destruction sequence that doesn't leak any global state between runs. We need this anyway for load game and player unit tests.

That being said, I wonder if IPC is also the way to go here. Then you could run a separate player binary and attach the interpreter debugger and other tools to it. We also again don't need to worry about player global state at all. Each player run starts and exits a new process for 100% guaranteed cleanliness.

The IPC approach would require us to add stuff to player to pipe the necessary data back and forth, as well as a protocol for the game strate (enhanced LSD?). That can be a lot of work but it would enforce a clean separation. If we did this though, it also opens the door to additional capabilities for regtesting and other introspection tools.

The biggest amount of work with doing IPC / networking is the serialization code, but we already have liblcf giving us a fast binary protocol.

If we don't go the IPC route, I would want to still see a very clean separation. Let's not pollute Player with random // needed for editor hacks.

Not going to IPC route would allow a much tighter and easier integration with edtior, and allow live editing while playing, which could be a big productivity booster for developers.

  • Running multiple editors / players for different games at the same time - use IPC

To run multiple editor instances for different games at the same time with their own embedded players, I would only do it by spawning multiple processes. Then we don't need to worry about player globals, ui globals, renderer state, audio state, etc.. etc... If needed a parent UI process can manage all the child ui instances. Trying to manage all the global state ourselves, especially for all the backend third party libraries I'm 99% sure will end up in frustration and failure, not to mention massive complexity. This also completely shields us to state cleanup bugs from multiple editor/player instances.

For Video/Audio/Input the Editor could provide an "EditorUi" object (like SDLUi etc).

If we embed a running player directly into editor widget, we'll need this.

Options are:

  1. QtWidget Ui to replace SDL - if player is in process
  2. IPC Ui, which just pipes the framebuffer onto IPC channel, and editor picks this up and renders it into it's widget, with potential debug overlays - if player is out of process
  3. Do nothing - if player is out of process, we can just run it in windowed mode using native SDL and have the editor debugging tools separate widgets.

Though the design for this "Player object" is on you @fmatthew5876 I'm not really motivated to approach this ^^

Regardless of editor, this is in my near term future plans. I want to make sure new game / load game bugs are impossible.

We're very close to being able to stand up and tear down player game instances. Once the character PR goes in I'll be unlocked to refactor the player global state to achieve this.

Reminder: Never write into the LMT when clicking in the map tree or scrolling the scrollbar (Provide readonly mode?)

The RPG Maker editor has this bad behaviour to always write the LMT even when you don't do anything except for "clicking maps" and "scrolling around". This is SUPER BAD for game preservation because the file hash changes!

It means that only the LDB hash is reliable, for LMT it requires extracting the map tree and hashing this one.

Our editor shouldn't do this. It is unlikely that we will need hashing for "EasyRPG Games" but for game preservation of old games I consider such a feature crucial.

Included templates are no longer readable by liblcf

Editor includes Template fields that are copiable to each new project. The templates use XML format, but the XML format of liblcf changed and it can no longer parse the old format (it contains fields like pdef_f, mdef_f, unknown_03 and some more). Because of this, Editor segfaults when creating or opening a project.

As a temporary workaround, converting RM2k database file into .xml with lcf2xml, and copying this file into bin/templates/EASY_RT.edb (overwriting the previous content) works.

This might be related to #98

RFC: Consider Qt Quick + Qml?

Qt Widgets are consideres as outdated since Qt 5 and don't really receive updates anymore, besides bugfixes.

The new hot shit since Qt 5 is QtQuick + Qml which is a declarative Ui language. Gives some nice features like e.g. data binding without writing any C++ code, saves repetitive code and makes it easier to create custom Ui elements if necessary.

Native UI elements are available: https://doc.qt.io/qt-5/qtquickcontrols-overview.html

Can't be that bad because KDE 5 migrates currently everything to Qml.

Just mentioning this because our editor is not that advanced yet from a GUI perspective, so it's not too late to discuss this.

Stopped working on windows 10 after create new project

I download the file here https://ci.easyrpg.org/view/Editor/job/editor-windows/lastSuccessfulBuild/artifact/bin/easyrpg_editor_windows.zip

How to reproduce:

  1. Set RTP to C:\Program Files (x86)\Common Files\Enterbrain\RGSS2\RPGVX
  2. New project -> Fill in all field as image
    New_project
  3. Click OK
  4. crash

I go to Control Panel\All Control Panel Items\Security and Maintenance\Problem Details and get problem detail

Description
Faulting Application Path:	E:\RPGGameProject\EasyRPG-Editor\EasyRPG-Editor.exe

Problem signature
Problem Event Name:	APPCRASH
Application Name:	EasyRPG-Editor.exe
Application Version:	0.0.0.0
Application Timestamp:	5800abb7
Fault Module Name:	EasyRPG-Editor.exe
Fault Module Version:	0.0.0.0
Fault Module Timestamp:	5800abb7
Exception Code:	c0000005
Exception Offset:	0003d807
OS Version:	10.0.14393.2.0.0.768.100
Locale ID:	1033
Additional Information 1:	2beb
Additional Information 2:	2beba6fb4680d73a8c78ca7c24ccdb46
Additional Information 3:	1055
Additional Information 4:	10551cc64bcfba7d2297b81a9c0092f2

Extra information about the problem
Bucket ID:	f49bb7a045500d196558d550d9e04323 (108476175033)

If you need any addition information that can help you fix the problem, don't hesitate to ask me. I get it for you.

Auto RTP emptying

When I'm going to develop a game that uses 100% of my own resources, I must unlink all references to the use of the RTP tab by tab in the editor.

It'd be great to be able to empty the entire database with a single click when developing a game with all the non-RTP resources.

Thanks.

Overlay for QGraphicsMapScene

I want some kind of overlay where some basic (important) information are shown, e.g. X/Y coordination, event-name (if any is below cursor) and some other data I don't know yet.
It should look something like this. It could be more transparent and/or should change it's location from the upper left side to the upper right side, if the mouse is somewhere near the overlay, so it doesn't bother the builder/creator/whoever.

I open this issue, because I don't know how the drawing in Qt works, and so I can't get it working. If someone is willing to give me a hint, I would provide a basic implementation (or the person just could write it :P )

Map Editor Zoom problems

Hi,
the biggest zoom for me is 200% but this is very small on my retina screen.

200% Zoom:
image

100% Zoom:
image

If I try to zoom smaller than 100% the editor crashes. The fist time I try this I get a error message but only on the first try. I can't reproduce the error message anymore =(

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.