Merge pull request #23 from huderlem/items
Populate items, flags, and vars in dropdown menus
This commit is contained in:
commit
470fc92fba
8 changed files with 357 additions and 157 deletions
59
asm.cpp
59
asm.cpp
|
@ -1,59 +0,0 @@
|
||||||
#include "asm.h"
|
|
||||||
|
|
||||||
Asm::Asm()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Asm::strip_comment(QString *line) {
|
|
||||||
bool in_string = false;
|
|
||||||
for (int i = 0; i < line->length(); i++) {
|
|
||||||
if (line->at(i) == '"') {
|
|
||||||
in_string = !in_string;
|
|
||||||
} else if (line->at(i) == '@') {
|
|
||||||
if (!in_string) {
|
|
||||||
line->truncate(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QStringList>* Asm::parse(QString text) {
|
|
||||||
QList<QStringList> *parsed = new QList<QStringList>;
|
|
||||||
QStringList lines = text.split('\n');
|
|
||||||
for (QString line : lines) {
|
|
||||||
QString label;
|
|
||||||
//QString macro;
|
|
||||||
//QStringList *params;
|
|
||||||
strip_comment(&line);
|
|
||||||
if (line.trimmed().isEmpty()) {
|
|
||||||
} else if (line.contains(':')) {
|
|
||||||
label = line.left(line.indexOf(':'));
|
|
||||||
QStringList *list = new QStringList;
|
|
||||||
list->append(".label"); // This is not a real keyword. It's used only to make the output more regular.
|
|
||||||
list->append(label);
|
|
||||||
parsed->append(*list);
|
|
||||||
// There should not be anything else on the line.
|
|
||||||
// gas will raise a syntax error if there is.
|
|
||||||
} else {
|
|
||||||
line = line.trimmed();
|
|
||||||
//parsed->append(line.split(QRegExp("\\s*,\\s*")));
|
|
||||||
QString macro;
|
|
||||||
QStringList params;
|
|
||||||
int index = line.indexOf(QRegExp("\\s+"));
|
|
||||||
macro = line.left(index);
|
|
||||||
params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*"));
|
|
||||||
params.prepend(macro);
|
|
||||||
parsed->append(params);
|
|
||||||
}
|
|
||||||
//if (macro != NULL) {
|
|
||||||
// if (macros->contains(macro)) {
|
|
||||||
// void* function = macros->value(macro);
|
|
||||||
// if (function != NULL) {
|
|
||||||
// std::function function(params);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
return parsed;
|
|
||||||
}
|
|
15
asm.h
15
asm.h
|
@ -1,15 +0,0 @@
|
||||||
#ifndef ASM_H
|
|
||||||
#define ASM_H
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
class Asm
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Asm();
|
|
||||||
void strip_comment(QString*);
|
|
||||||
QList<QStringList>* parse(QString);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ASM_H
|
|
|
@ -203,11 +203,7 @@ void MainWindow::displayMapProperties() {
|
||||||
|
|
||||||
QStringList songs = project->getSongNames();
|
QStringList songs = project->getSongNames();
|
||||||
ui->comboBox_Song->addItems(songs);
|
ui->comboBox_Song->addItems(songs);
|
||||||
QString song = map->song;
|
ui->comboBox_Song->setCurrentText(map->song);
|
||||||
if (!songs.contains(song)) {
|
|
||||||
song = project->getSongName(song.toInt());
|
|
||||||
}
|
|
||||||
ui->comboBox_Song->setCurrentText(song);
|
|
||||||
|
|
||||||
ui->comboBox_Location->addItems(project->getLocations());
|
ui->comboBox_Location->addItems(project->getLocations());
|
||||||
ui->comboBox_Location->setCurrentText(map->location);
|
ui->comboBox_Location->setCurrentText(map->location);
|
||||||
|
@ -284,6 +280,9 @@ void MainWindow::loadDataStructures() {
|
||||||
Project *project = editor->project;
|
Project *project = editor->project;
|
||||||
project->readMapAttributesTable();
|
project->readMapAttributesTable();
|
||||||
project->readAllMapAttributes();
|
project->readAllMapAttributes();
|
||||||
|
project->readItemNames();
|
||||||
|
project->readFlagNames();
|
||||||
|
project->readVarNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::populateMapList() {
|
void MainWindow::populateMapList() {
|
||||||
|
@ -569,8 +568,8 @@ void MainWindow::updateSelectedObjects() {
|
||||||
field_labels["sight_radius"] = "Sight Radius";
|
field_labels["sight_radius"] = "Sight Radius";
|
||||||
field_labels["destination_warp"] = "Destination Warp";
|
field_labels["destination_warp"] = "Destination Warp";
|
||||||
field_labels["destination_map_name"] = "Destination Map";
|
field_labels["destination_map_name"] = "Destination Map";
|
||||||
field_labels["coord_unknown1"] = "Unknown 1";
|
field_labels["script_var"] = "Var";
|
||||||
field_labels["coord_unknown2"] = "Unknown 2";
|
field_labels["script_var_value"] = "Var Value";
|
||||||
field_labels["type"] = "Type";
|
field_labels["type"] = "Type";
|
||||||
field_labels["item"] = "Item";
|
field_labels["item"] = "Item";
|
||||||
field_labels["item_unknown5"] = "Unknown 5";
|
field_labels["item_unknown5"] = "Unknown 5";
|
||||||
|
@ -613,8 +612,8 @@ void MainWindow::updateSelectedObjects() {
|
||||||
}
|
}
|
||||||
else if (event_type == "trap") {
|
else if (event_type == "trap") {
|
||||||
fields << "script_label";
|
fields << "script_label";
|
||||||
fields << "coord_unknown1";
|
fields << "script_var";
|
||||||
fields << "coord_unknown2";
|
fields << "script_var_value";
|
||||||
}
|
}
|
||||||
else if (event_type == "trap_weather") {
|
else if (event_type == "trap_weather") {
|
||||||
fields << "weather";
|
fields << "weather";
|
||||||
|
@ -644,6 +643,21 @@ void MainWindow::updateSelectedObjects() {
|
||||||
combo->addItem(value);
|
combo->addItem(value);
|
||||||
}
|
}
|
||||||
combo->addItems(*editor->project->mapNames);
|
combo->addItems(*editor->project->mapNames);
|
||||||
|
} else if (key == "item") {
|
||||||
|
if (!editor->project->itemNames->contains(value)) {
|
||||||
|
combo->addItem(value);
|
||||||
|
}
|
||||||
|
combo->addItems(*editor->project->itemNames);
|
||||||
|
} else if (key == "flag") {
|
||||||
|
if (!editor->project->flagNames->contains(value)) {
|
||||||
|
combo->addItem(value);
|
||||||
|
}
|
||||||
|
combo->addItems(*editor->project->flagNames);
|
||||||
|
} else if (key == "script_var") {
|
||||||
|
if (!editor->project->varNames->contains(value)) {
|
||||||
|
combo->addItem(value);
|
||||||
|
}
|
||||||
|
combo->addItems(*editor->project->varNames);
|
||||||
} else {
|
} else {
|
||||||
combo->addItem(value);
|
combo->addItem(value);
|
||||||
}
|
}
|
||||||
|
|
199
parseutil.cpp
Executable file
199
parseutil.cpp
Executable file
|
@ -0,0 +1,199 @@
|
||||||
|
#include "parseutil.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QStack>
|
||||||
|
|
||||||
|
ParseUtil::ParseUtil()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseUtil::strip_comment(QString *line) {
|
||||||
|
bool in_string = false;
|
||||||
|
for (int i = 0; i < line->length(); i++) {
|
||||||
|
if (line->at(i) == '"') {
|
||||||
|
in_string = !in_string;
|
||||||
|
} else if (line->at(i) == '@') {
|
||||||
|
if (!in_string) {
|
||||||
|
line->truncate(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QStringList>* ParseUtil::parseAsm(QString text) {
|
||||||
|
QList<QStringList> *parsed = new QList<QStringList>;
|
||||||
|
QStringList lines = text.split('\n');
|
||||||
|
for (QString line : lines) {
|
||||||
|
QString label;
|
||||||
|
//QString macro;
|
||||||
|
//QStringList *params;
|
||||||
|
strip_comment(&line);
|
||||||
|
if (line.trimmed().isEmpty()) {
|
||||||
|
} else if (line.contains(':')) {
|
||||||
|
label = line.left(line.indexOf(':'));
|
||||||
|
QStringList *list = new QStringList;
|
||||||
|
list->append(".label"); // This is not a real keyword. It's used only to make the output more regular.
|
||||||
|
list->append(label);
|
||||||
|
parsed->append(*list);
|
||||||
|
// There should not be anything else on the line.
|
||||||
|
// gas will raise a syntax error if there is.
|
||||||
|
} else {
|
||||||
|
line = line.trimmed();
|
||||||
|
//parsed->append(line.split(QRegExp("\\s*,\\s*")));
|
||||||
|
QString macro;
|
||||||
|
QStringList params;
|
||||||
|
int index = line.indexOf(QRegExp("\\s+"));
|
||||||
|
macro = line.left(index);
|
||||||
|
params = line.right(line.length() - index).trimmed().split(QRegExp("\\s*,\\s*"));
|
||||||
|
params.prepend(macro);
|
||||||
|
parsed->append(params);
|
||||||
|
}
|
||||||
|
//if (macro != NULL) {
|
||||||
|
// if (macros->contains(macro)) {
|
||||||
|
// void* function = macros->value(macro);
|
||||||
|
// if (function != NULL) {
|
||||||
|
// std::function function(params);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ParseUtil::evaluateDefine(QString define, QMap<QString, int>* knownDefines) {
|
||||||
|
QList<Token> tokens = tokenizeExpression(define, knownDefines);
|
||||||
|
QList<Token> postfixExpression = generatePostfix(tokens);
|
||||||
|
return evaluatePostfix(postfixExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Token> ParseUtil::tokenizeExpression(QString expression, QMap<QString, int>* knownIdentifiers) {
|
||||||
|
QList<Token> tokens;
|
||||||
|
|
||||||
|
QStringList tokenTypes = (QStringList() << "hex" << "decimal" << "identifier" << "operator" << "leftparen" << "rightparen");
|
||||||
|
QRegularExpression re("^(?<hex>0x[0-9a-fA-F]+)|(?<decimal>[0-9]+)|(?<identifier>[a-zA-Z_0-9]+)|(?<operator>[+\\-*\\/<>|^%]+)|(?<leftparen>\\()|(?<rightparen>\\))");
|
||||||
|
|
||||||
|
expression = expression.trimmed();
|
||||||
|
while (!expression.isEmpty()) {
|
||||||
|
QRegularExpressionMatch match = re.match(expression);
|
||||||
|
if (!match.hasMatch()) {
|
||||||
|
qDebug() << "Failed to tokenize expression: " << expression;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (QString tokenType : tokenTypes) {
|
||||||
|
QString token = match.captured(tokenType);
|
||||||
|
if (!token.isEmpty()) {
|
||||||
|
if (tokenType == "identifier") {
|
||||||
|
if (knownIdentifiers->contains(token)) {
|
||||||
|
QString actualToken = QString("%1").arg(knownIdentifiers->value(token));
|
||||||
|
expression = expression.replace(0, token.length(), actualToken);
|
||||||
|
token = actualToken;
|
||||||
|
tokenType = "decimal";
|
||||||
|
} else {
|
||||||
|
qDebug() << "Unknown identifier found in expression: " << token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.append(Token(token, tokenType));
|
||||||
|
expression = expression.remove(0, token.length()).trimmed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString, int> Token::precedenceMap = QMap<QString, int>(
|
||||||
|
{
|
||||||
|
{"*", 3},
|
||||||
|
{"/", 3},
|
||||||
|
{"+", 4},
|
||||||
|
{"-", 4},
|
||||||
|
{"<<", 5},
|
||||||
|
{">>", 5},
|
||||||
|
{"&", 8},
|
||||||
|
{"^", 9},
|
||||||
|
{"|", 10}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Shunting-yard algorithm for generating postfix notation.
|
||||||
|
// https://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
||||||
|
QList<Token> ParseUtil::generatePostfix(QList<Token> tokens) {
|
||||||
|
QList<Token> output;
|
||||||
|
QStack<Token> operatorStack;
|
||||||
|
for (Token token : tokens) {
|
||||||
|
if (token.type == TokenType::Number) {
|
||||||
|
output.append(token);
|
||||||
|
} else if (token.value == "(") {
|
||||||
|
operatorStack.push(token);
|
||||||
|
} else if (token.value == ")") {
|
||||||
|
while (!operatorStack.empty() && operatorStack.top().value != "(") {
|
||||||
|
output.append(operatorStack.pop());
|
||||||
|
}
|
||||||
|
if (!operatorStack.empty()) {
|
||||||
|
// pop the left parenthesis token
|
||||||
|
operatorStack.pop();
|
||||||
|
} else {
|
||||||
|
qDebug() << "Mismatched parentheses detected in expression!";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// token is an operator
|
||||||
|
while (!operatorStack.isEmpty()
|
||||||
|
&& operatorStack.top().operatorPrecedence <= token.operatorPrecedence
|
||||||
|
&& operatorStack.top().value != "(") {
|
||||||
|
output.append(operatorStack.pop());
|
||||||
|
}
|
||||||
|
operatorStack.push(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!operatorStack.isEmpty()) {
|
||||||
|
if (operatorStack.top().value == "(" || operatorStack.top().value == ")") {
|
||||||
|
qDebug() << "Mismatched parentheses detected in expression!";
|
||||||
|
} else {
|
||||||
|
output.append(operatorStack.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate postfix expression.
|
||||||
|
// https://en.wikipedia.org/wiki/Reverse_Polish_notation#Postfix_evaluation_algorithm
|
||||||
|
int ParseUtil::evaluatePostfix(QList<Token> postfix) {
|
||||||
|
QStack<Token> stack;
|
||||||
|
for (Token token : postfix) {
|
||||||
|
if (token.type == TokenType::Operator) {
|
||||||
|
int op2 = stack.pop().value.toInt(nullptr, 0);
|
||||||
|
int op1 = stack.pop().value.toInt(nullptr, 0);
|
||||||
|
int result = 0;
|
||||||
|
if (token.value == "*") {
|
||||||
|
result = op1 * op2;
|
||||||
|
} else if (token.value == "/") {
|
||||||
|
result = op1 / op2;
|
||||||
|
} else if (token.value == "+") {
|
||||||
|
result = op1 + op2;
|
||||||
|
} else if (token.value == "-") {
|
||||||
|
result = op1 - op2;
|
||||||
|
} else if (token.value == "<<") {
|
||||||
|
result = op1 << op2;
|
||||||
|
} else if (token.value == ">>") {
|
||||||
|
result = op1 >> op2;
|
||||||
|
} else if (token.value == "&") {
|
||||||
|
result = op1 & op2;
|
||||||
|
} else if (token.value == "^") {
|
||||||
|
result = op1 ^ op2;
|
||||||
|
} else if (token.value == "|") {
|
||||||
|
result = op1 | op2;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Unsupported postfix operator: " << token.value;
|
||||||
|
}
|
||||||
|
stack.push(Token(QString("%1").arg(result), "decimal"));
|
||||||
|
} else {
|
||||||
|
stack.push(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack.pop().value.toInt(nullptr, 0);
|
||||||
|
}
|
43
parseutil.h
Executable file
43
parseutil.h
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef PARSEUTIL_H
|
||||||
|
#define PARSEUTIL_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
enum TokenType {
|
||||||
|
Number,
|
||||||
|
Operator,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Token {
|
||||||
|
public:
|
||||||
|
Token(QString value = "", QString type = "") {
|
||||||
|
this->value = value;
|
||||||
|
this->type = TokenType::Operator;
|
||||||
|
if (type == "decimal" || type == "hex") {
|
||||||
|
this->type = TokenType::Number;
|
||||||
|
this->operatorPrecedence = -1;
|
||||||
|
} else if (type == "operator") {
|
||||||
|
this->operatorPrecedence = precedenceMap[value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static QMap<QString, int> precedenceMap;
|
||||||
|
QString value;
|
||||||
|
TokenType type;
|
||||||
|
int operatorPrecedence; // only relevant for operator tokens
|
||||||
|
};
|
||||||
|
|
||||||
|
class ParseUtil
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParseUtil();
|
||||||
|
void strip_comment(QString*);
|
||||||
|
QList<QStringList>* parseAsm(QString);
|
||||||
|
int evaluateDefine(QString, QMap<QString, int>*);
|
||||||
|
private:
|
||||||
|
QList<Token> tokenizeExpression(QString expression, QMap<QString, int>* knownIdentifiers);
|
||||||
|
QList<Token> generatePostfix(QList<Token> tokens);
|
||||||
|
int evaluatePostfix(QList<Token> postfix);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PARSEUTIL_H
|
|
@ -15,7 +15,6 @@ TEMPLATE = app
|
||||||
SOURCES += main.cpp\
|
SOURCES += main.cpp\
|
||||||
mainwindow.cpp \
|
mainwindow.cpp \
|
||||||
project.cpp \
|
project.cpp \
|
||||||
asm.cpp \
|
|
||||||
map.cpp \
|
map.cpp \
|
||||||
blockdata.cpp \
|
blockdata.cpp \
|
||||||
block.cpp \
|
block.cpp \
|
||||||
|
@ -25,11 +24,11 @@ SOURCES += main.cpp\
|
||||||
event.cpp \
|
event.cpp \
|
||||||
editor.cpp \
|
editor.cpp \
|
||||||
objectpropertiesframe.cpp \
|
objectpropertiesframe.cpp \
|
||||||
graphicsview.cpp
|
graphicsview.cpp \
|
||||||
|
parseutil.cpp
|
||||||
|
|
||||||
HEADERS += mainwindow.h \
|
HEADERS += mainwindow.h \
|
||||||
project.h \
|
project.h \
|
||||||
asm.h \
|
|
||||||
map.h \
|
map.h \
|
||||||
blockdata.h \
|
blockdata.h \
|
||||||
block.h \
|
block.h \
|
||||||
|
@ -39,7 +38,8 @@ HEADERS += mainwindow.h \
|
||||||
event.h \
|
event.h \
|
||||||
editor.h \
|
editor.h \
|
||||||
objectpropertiesframe.h \
|
objectpropertiesframe.h \
|
||||||
graphicsview.h
|
graphicsview.h \
|
||||||
|
parseutil.h
|
||||||
|
|
||||||
FORMS += mainwindow.ui \
|
FORMS += mainwindow.ui \
|
||||||
objectpropertiesframe.ui
|
objectpropertiesframe.ui
|
||||||
|
|
148
project.cpp
148
project.cpp
|
@ -1,4 +1,4 @@
|
||||||
#include "asm.h"
|
#include "parseutil.h"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "tileset.h"
|
#include "tileset.h"
|
||||||
|
@ -18,6 +18,9 @@ Project::Project()
|
||||||
groupNames = new QStringList;
|
groupNames = new QStringList;
|
||||||
map_groups = new QMap<QString, int>;
|
map_groups = new QMap<QString, int>;
|
||||||
mapNames = new QStringList;
|
mapNames = new QStringList;
|
||||||
|
itemNames = new QStringList;
|
||||||
|
flagNames = new QStringList;
|
||||||
|
varNames = new QStringList;
|
||||||
map_cache = new QMap<QString, Map*>;
|
map_cache = new QMap<QString, Map*>;
|
||||||
mapConstantsToMapNames = new QMap<QString, QString>;
|
mapConstantsToMapNames = new QMap<QString, QString>;
|
||||||
mapNamesToMapConstants = new QMap<QString, QString>;
|
mapNamesToMapConstants = new QMap<QString, QString>;
|
||||||
|
@ -68,7 +71,7 @@ void Project::loadMapConnections(Map *map) {
|
||||||
QString path = root + QString("/data/maps/%1/connections.inc").arg(map->name);
|
QString path = root + QString("/data/maps/%1/connections.inc").arg(map->name);
|
||||||
QString text = readTextFile(path);
|
QString text = readTextFile(path);
|
||||||
if (!text.isNull()) {
|
if (!text.isNull()) {
|
||||||
QList<QStringList> *commands = parse(text);
|
QList<QStringList> *commands = parseAsm(text);
|
||||||
QStringList *list = getLabelValues(commands, map->connections_label);
|
QStringList *list = getLabelValues(commands, map->connections_label);
|
||||||
|
|
||||||
//// Avoid using this value. It ought to be generated instead.
|
//// Avoid using this value. It ought to be generated instead.
|
||||||
|
@ -147,13 +150,13 @@ void Project::readMapHeader(Map* map) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QString label = map->name;
|
QString label = map->name;
|
||||||
Asm *parser = new Asm;
|
ParseUtil *parser = new ParseUtil;
|
||||||
|
|
||||||
QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc");
|
QString header_text = readTextFile(root + "/data/maps/" + label + "/header.inc");
|
||||||
if (header_text.isNull()) {
|
if (header_text.isNull()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QStringList *header = getLabelValues(parser->parse(header_text), label);
|
QStringList *header = getLabelValues(parser->parseAsm(header_text), label);
|
||||||
map->attributes_label = header->value(0);
|
map->attributes_label = header->value(0);
|
||||||
map->events_label = header->value(1);
|
map->events_label = header->value(1);
|
||||||
map->scripts_label = header->value(2);
|
map->scripts_label = header->value(2);
|
||||||
|
@ -209,7 +212,7 @@ void Project::saveMapHeader(Map *map) {
|
||||||
void Project::readMapAttributesTable() {
|
void Project::readMapAttributesTable() {
|
||||||
int curMapIndex = 1;
|
int curMapIndex = 1;
|
||||||
QString attributesText = readTextFile(getMapAttributesTableFilepath());
|
QString attributesText = readTextFile(getMapAttributesTableFilepath());
|
||||||
QList<QStringList>* values = parse(attributesText);
|
QList<QStringList>* values = parseAsm(attributesText);
|
||||||
bool inAttributePointers = false;
|
bool inAttributePointers = false;
|
||||||
for (int i = 0; i < values->length(); i++) {
|
for (int i = 0; i < values->length(); i++) {
|
||||||
QStringList params = values->value(i);
|
QStringList params = values->value(i);
|
||||||
|
@ -262,13 +265,13 @@ void Project::readMapAttributes(Map* map) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Asm *parser = new Asm;
|
ParseUtil *parser = new ParseUtil;
|
||||||
|
|
||||||
QString assets_text = readTextFile(getMapAssetsFilepath());
|
QString assets_text = readTextFile(getMapAssetsFilepath());
|
||||||
if (assets_text.isNull()) {
|
if (assets_text.isNull()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QStringList *attributes = getLabelValues(parser->parse(assets_text), map->attributes_label);
|
QStringList *attributes = getLabelValues(parser->parseAsm(assets_text), map->attributes_label);
|
||||||
map->width = attributes->value(0);
|
map->width = attributes->value(0);
|
||||||
map->height = attributes->value(1);
|
map->height = attributes->value(1);
|
||||||
map->border_label = attributes->value(2);
|
map->border_label = attributes->value(2);
|
||||||
|
@ -280,13 +283,13 @@ void Project::readMapAttributes(Map* map) {
|
||||||
void Project::readAllMapAttributes() {
|
void Project::readAllMapAttributes() {
|
||||||
mapAttributes.clear();
|
mapAttributes.clear();
|
||||||
|
|
||||||
Asm *parser = new Asm;
|
ParseUtil *parser = new ParseUtil;
|
||||||
QString assets_text = readTextFile(getMapAssetsFilepath());
|
QString assets_text = readTextFile(getMapAssetsFilepath());
|
||||||
if (assets_text.isNull()) {
|
if (assets_text.isNull()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QStringList> *commands = parser->parse(assets_text);
|
QList<QStringList> *commands = parser->parseAsm(assets_text);
|
||||||
|
|
||||||
// Assume the _assets.inc file is grouped consistently in the order of:
|
// Assume the _assets.inc file is grouped consistently in the order of:
|
||||||
// 1. <map_name>_MapBorder
|
// 1. <map_name>_MapBorder
|
||||||
|
@ -536,10 +539,10 @@ void Project::getTilesets(Map* map) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Tileset* Project::loadTileset(QString label) {
|
Tileset* Project::loadTileset(QString label) {
|
||||||
Asm *parser = new Asm;
|
ParseUtil *parser = new ParseUtil;
|
||||||
|
|
||||||
QString headers_text = readTextFile(root + "/data/tilesets/headers.inc");
|
QString headers_text = readTextFile(root + "/data/tilesets/headers.inc");
|
||||||
QStringList *values = getLabelValues(parser->parse(headers_text), label);
|
QStringList *values = getLabelValues(parser->parseAsm(headers_text), label);
|
||||||
Tileset *tileset = new Tileset;
|
Tileset *tileset = new Tileset;
|
||||||
tileset->name = label;
|
tileset->name = label;
|
||||||
tileset->is_compressed = values->value(0);
|
tileset->is_compressed = values->value(0);
|
||||||
|
@ -559,7 +562,7 @@ Tileset* Project::loadTileset(QString label) {
|
||||||
|
|
||||||
QString Project::getBlockdataPath(Map* map) {
|
QString Project::getBlockdataPath(Map* map) {
|
||||||
QString text = readTextFile(getMapAssetsFilepath());
|
QString text = readTextFile(getMapAssetsFilepath());
|
||||||
QStringList *values = getLabelValues(parse(text), map->blockdata_label);
|
QStringList *values = getLabelValues(parseAsm(text), map->blockdata_label);
|
||||||
QString path;
|
QString path;
|
||||||
if (!values->isEmpty()) {
|
if (!values->isEmpty()) {
|
||||||
path = root + "/" + values->value(0).section('"', 1, 1);
|
path = root + "/" + values->value(0).section('"', 1, 1);
|
||||||
|
@ -571,7 +574,7 @@ QString Project::getBlockdataPath(Map* map) {
|
||||||
|
|
||||||
QString Project::getMapBorderPath(Map *map) {
|
QString Project::getMapBorderPath(Map *map) {
|
||||||
QString text = readTextFile(getMapAssetsFilepath());
|
QString text = readTextFile(getMapAssetsFilepath());
|
||||||
QStringList *values = getLabelValues(parse(text), map->border_label);
|
QStringList *values = getLabelValues(parseAsm(text), map->border_label);
|
||||||
QString path;
|
QString path;
|
||||||
if (!values->isEmpty()) {
|
if (!values->isEmpty()) {
|
||||||
path = root + "/" + values->value(0).section('"', 1, 1);
|
path = root + "/" + values->value(0).section('"', 1, 1);
|
||||||
|
@ -702,7 +705,7 @@ void Project::saveAllDataStructures() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Project::loadTilesetAssets(Tileset* tileset) {
|
void Project::loadTilesetAssets(Tileset* tileset) {
|
||||||
Asm* parser = new Asm;
|
ParseUtil* parser = new ParseUtil;
|
||||||
QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary";
|
QString category = (tileset->is_secondary == "TRUE") ? "secondary" : "primary";
|
||||||
if (tileset->name.isNull()) {
|
if (tileset->name.isNull()) {
|
||||||
return;
|
return;
|
||||||
|
@ -710,7 +713,7 @@ void Project::loadTilesetAssets(Tileset* tileset) {
|
||||||
QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower();
|
QString dir_path = root + "/data/tilesets/" + category + "/" + tileset->name.replace("gTileset_", "").toLower();
|
||||||
|
|
||||||
QString graphics_text = readTextFile(root + "/data/tilesets/graphics.inc");
|
QString graphics_text = readTextFile(root + "/data/tilesets/graphics.inc");
|
||||||
QList<QStringList> *graphics = parser->parse(graphics_text);
|
QList<QStringList> *graphics = parser->parseAsm(graphics_text);
|
||||||
QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label);
|
QStringList *tiles_values = getLabelValues(graphics, tileset->tiles_label);
|
||||||
QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label);
|
QStringList *palettes_values = getLabelValues(graphics, tileset->palettes_label);
|
||||||
|
|
||||||
|
@ -740,7 +743,7 @@ void Project::loadTilesetAssets(Tileset* tileset) {
|
||||||
QString metatiles_path;
|
QString metatiles_path;
|
||||||
QString metatile_attrs_path;
|
QString metatile_attrs_path;
|
||||||
QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc");
|
QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc");
|
||||||
QList<QStringList> *metatiles_macros = parser->parse(metatiles_text);
|
QList<QStringList> *metatiles_macros = parser->parseAsm(metatiles_text);
|
||||||
QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label);
|
QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label);
|
||||||
if (!metatiles_values->isEmpty()) {
|
if (!metatiles_values->isEmpty()) {
|
||||||
metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1);
|
metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1);
|
||||||
|
@ -915,8 +918,8 @@ void Project::readMapGroups() {
|
||||||
if (text.isNull()) {
|
if (text.isNull()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Asm *parser = new Asm;
|
ParseUtil *parser = new ParseUtil;
|
||||||
QList<QStringList> *commands = parser->parse(text);
|
QList<QStringList> *commands = parser->parseAsm(text);
|
||||||
|
|
||||||
bool in_group_pointers = false;
|
bool in_group_pointers = false;
|
||||||
QStringList *groups = new QStringList;
|
QStringList *groups = new QStringList;
|
||||||
|
@ -1012,9 +1015,9 @@ QString Project::getNewMapName() {
|
||||||
return newMapName;
|
return newMapName;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QStringList>* Project::parse(QString text) {
|
QList<QStringList>* Project::parseAsm(QString text) {
|
||||||
Asm *parser = new Asm;
|
ParseUtil *parser = new ParseUtil;
|
||||||
return parser->parse(text);
|
return parser->parseAsm(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Project::getLocations() {
|
QStringList Project::getLocations() {
|
||||||
|
@ -1062,6 +1065,39 @@ QStringList Project::getBattleScenes() {
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Project::readItemNames() {
|
||||||
|
QString filepath = root + "/include/constants/items.h";
|
||||||
|
QStringList prefixes = (QStringList() << "ITEM_");
|
||||||
|
readCDefinesSorted(filepath, prefixes, itemNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Project::readFlagNames() {
|
||||||
|
QString filepath = root + "/include/constants/flags.h";
|
||||||
|
QStringList prefixes = (QStringList() << "FLAG_");
|
||||||
|
readCDefinesSorted(filepath, prefixes, flagNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Project::readVarNames() {
|
||||||
|
QString filepath = root + "/include/constants/vars.h";
|
||||||
|
QStringList prefixes = (QStringList() << "VAR_");
|
||||||
|
readCDefinesSorted(filepath, prefixes, varNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet) {
|
||||||
|
QString text = readTextFile(filepath);
|
||||||
|
if (!text.isNull()) {
|
||||||
|
QMap<QString, int> defines = readCDefines(text, prefixes);
|
||||||
|
|
||||||
|
// The defines should to be sorted by their underlying value, not alphabetically.
|
||||||
|
// Reverse the map and read out the resulting keys in order.
|
||||||
|
QMultiMap<int, QString> definesInverse;
|
||||||
|
for (QString defineName : defines.keys()) {
|
||||||
|
definesInverse.insert(defines[defineName], defineName);
|
||||||
|
}
|
||||||
|
*definesToSet = definesInverse.values();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QStringList Project::getSongNames() {
|
QStringList Project::getSongNames() {
|
||||||
QStringList names;
|
QStringList names;
|
||||||
QString text = readTextFile(root + "/include/constants/songs.h");
|
QString text = readTextFile(root + "/include/constants/songs.h");
|
||||||
|
@ -1074,26 +1110,6 @@ QStringList Project::getSongNames() {
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Project::getSongName(int songNumber) {
|
|
||||||
QStringList names;
|
|
||||||
QString text = readTextFile(root + "/include/constants/songs.h");
|
|
||||||
if (!text.isNull()) {
|
|
||||||
QStringList songDefinePrefixes;
|
|
||||||
songDefinePrefixes << "SE_" << "BGM_";
|
|
||||||
QMap<QString, int> songDefines = readCDefines(text, songDefinePrefixes);
|
|
||||||
|
|
||||||
// Loop through song defines, and fine the one with the matching song number.
|
|
||||||
QMap<QString, int>::iterator iter = songDefines.begin();
|
|
||||||
while (iter != songDefines.end()) {
|
|
||||||
if (iter.value() == songNumber) {
|
|
||||||
return iter.key();
|
|
||||||
}
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
QMap<QString, int> Project::getMapObjGfxConstants() {
|
QMap<QString, int> Project::getMapObjGfxConstants() {
|
||||||
QMap<QString, int> constants;
|
QMap<QString, int> constants;
|
||||||
QString text = readTextFile(root + "/include/constants/map_objects.h");
|
QString text = readTextFile(root + "/include/constants/map_objects.h");
|
||||||
|
@ -1128,7 +1144,7 @@ void Project::loadObjectPixmaps(QList<Event*> objects) {
|
||||||
QString pointers_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info_pointers.h");
|
QString pointers_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info_pointers.h");
|
||||||
QString info_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info.h");
|
QString info_text = readTextFile(root + "/src/data/field_map_obj/map_object_graphics_info.h");
|
||||||
QString pic_text = readTextFile(root + "/src/data/field_map_obj/map_object_pic_tables.h");
|
QString pic_text = readTextFile(root + "/src/data/field_map_obj/map_object_pic_tables.h");
|
||||||
QString assets_text = readTextFile(root + "/src/field/field_map_obj.c");
|
QString assets_text = readTextFile(root + "/src/field/event_object_movement.c");
|
||||||
|
|
||||||
QStringList pointers = readCArray(pointers_text, "gMapObjectGraphicsInfoPointers");
|
QStringList pointers = readCArray(pointers_text, "gMapObjectGraphicsInfoPointers");
|
||||||
|
|
||||||
|
@ -1228,8 +1244,8 @@ void Project::saveMapEvents(Map *map) {
|
||||||
text += QString(", %1").arg(coords->get("y"));
|
text += QString(", %1").arg(coords->get("y"));
|
||||||
text += QString(", %1").arg(coords->get("elevation"));
|
text += QString(", %1").arg(coords->get("elevation"));
|
||||||
text += QString(", 0");
|
text += QString(", 0");
|
||||||
text += QString(", %1").arg(coords->get("coord_unknown1"));
|
text += QString(", %1").arg(coords->get("script_var"));
|
||||||
text += QString(", %1").arg(coords->get("coord_unknown2"));
|
text += QString(", %1").arg(coords->get("script_var_value"));
|
||||||
text += QString(", 0");
|
text += QString(", 0");
|
||||||
text += QString(", %1").arg(coords->get("script_label"));
|
text += QString(", %1").arg(coords->get("script_label"));
|
||||||
text += "\n";
|
text += "\n";
|
||||||
|
@ -1298,13 +1314,13 @@ void Project::readMapEvents(Map *map) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList *labels = getLabelValues(parse(text), map->events_label);
|
QStringList *labels = getLabelValues(parseAsm(text), map->events_label);
|
||||||
map->object_events_label = labels->value(0);
|
map->object_events_label = labels->value(0);
|
||||||
map->warps_label = labels->value(1);
|
map->warps_label = labels->value(1);
|
||||||
map->coord_events_label = labels->value(2);
|
map->coord_events_label = labels->value(2);
|
||||||
map->bg_events_label = labels->value(3);
|
map->bg_events_label = labels->value(3);
|
||||||
|
|
||||||
QList<QStringList> *object_events = getLabelMacros(parse(text), map->object_events_label);
|
QList<QStringList> *object_events = getLabelMacros(parseAsm(text), map->object_events_label);
|
||||||
map->events["object"].clear();
|
map->events["object"].clear();
|
||||||
for (QStringList command : *object_events) {
|
for (QStringList command : *object_events) {
|
||||||
if (command.value(0) == "object_event") {
|
if (command.value(0) == "object_event") {
|
||||||
|
@ -1348,7 +1364,7 @@ void Project::readMapEvents(Map *map) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QStringList> *warps = getLabelMacros(parse(text), map->warps_label);
|
QList<QStringList> *warps = getLabelMacros(parseAsm(text), map->warps_label);
|
||||||
map->events["warp"].clear();
|
map->events["warp"].clear();
|
||||||
for (QStringList command : *warps) {
|
for (QStringList command : *warps) {
|
||||||
if (command.value(0) == "warp_def") {
|
if (command.value(0) == "warp_def") {
|
||||||
|
@ -1372,7 +1388,7 @@ void Project::readMapEvents(Map *map) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QStringList> *coords = getLabelMacros(parse(text), map->coord_events_label);
|
QList<QStringList> *coords = getLabelMacros(parseAsm(text), map->coord_events_label);
|
||||||
map->events["trap"].clear();
|
map->events["trap"].clear();
|
||||||
map->events["trap_weather"].clear();
|
map->events["trap_weather"].clear();
|
||||||
for (QStringList command : *coords) {
|
for (QStringList command : *coords) {
|
||||||
|
@ -1389,8 +1405,8 @@ void Project::readMapEvents(Map *map) {
|
||||||
coord->put("x", command.value(i++));
|
coord->put("x", command.value(i++));
|
||||||
coord->put("y", command.value(i++));
|
coord->put("y", command.value(i++));
|
||||||
coord->put("elevation", command.value(i++));
|
coord->put("elevation", command.value(i++));
|
||||||
coord->put("coord_unknown1", command.value(i++));
|
coord->put("script_var", command.value(i++));
|
||||||
coord->put("coord_unknown2", command.value(i++));
|
coord->put("script_var_value", command.value(i++));
|
||||||
coord->put("script_label", command.value(i++));
|
coord->put("script_label", command.value(i++));
|
||||||
//coord_unknown3
|
//coord_unknown3
|
||||||
//coord_unknown4
|
//coord_unknown4
|
||||||
|
@ -1410,7 +1426,7 @@ void Project::readMapEvents(Map *map) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QStringList> *bgs = getLabelMacros(parse(text), map->bg_events_label);
|
QList<QStringList> *bgs = getLabelMacros(parseAsm(text), map->bg_events_label);
|
||||||
map->events["sign"].clear();
|
map->events["sign"].clear();
|
||||||
map->events["event_hidden_item"].clear();
|
map->events["event_hidden_item"].clear();
|
||||||
map->events["event_secret_base"].clear();
|
map->events["event_secret_base"].clear();
|
||||||
|
@ -1515,27 +1531,23 @@ QString Project::readCIncbin(QString text, QString label) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, int> Project::readCDefines(QString text, QStringList prefixes) {
|
QMap<QString, int> Project::readCDefines(QString text, QStringList prefixes) {
|
||||||
QMap<QString, int> defines;
|
ParseUtil parser;
|
||||||
|
QMap<QString, int> allDefines;
|
||||||
QString combinedPrefixes = "[" + prefixes.join('|') + "]";
|
QMap<QString, int> filteredDefines;
|
||||||
QRegularExpression re(QString("#define\\s+(?<defineName>%1\\w+)\\s(?<defineValue>\\w+)").arg(combinedPrefixes));
|
QRegularExpression re("#define\\s+(?<defineName>\\w+)[^\\S\\n]+(?<defineValue>.+)");
|
||||||
QRegularExpressionMatchIterator iter = re.globalMatch(text);
|
QRegularExpressionMatchIterator iter = re.globalMatch(text);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
QRegularExpressionMatch match = iter.next();
|
QRegularExpressionMatch match = iter.next();
|
||||||
QString name = match.captured("defineName");
|
QString name = match.captured("defineName");
|
||||||
QString value = match.captured("defineValue");
|
QString expression = match.captured("defineValue");
|
||||||
bool valid;
|
expression.replace(QRegularExpression("//.*"), "");
|
||||||
int parsedValue = value.startsWith("0x") ? value.toInt(&valid, 16) : value.toInt(&valid, 10);
|
int value = parser.evaluateDefine(expression, &allDefines);
|
||||||
if (valid) {
|
allDefines.insert(name, value);
|
||||||
if (!defines.contains(name)) {
|
for (QString prefix : prefixes) {
|
||||||
defines.insert(name, parsedValue);
|
if (name.startsWith(prefix)) {
|
||||||
} else {
|
filteredDefines.insert(name, value);
|
||||||
qDebug() << QString("Define '%1' is defined multiple times'").arg(name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qDebug() << QString("Failed to parse define '%1' value '%2' as base 10 or hexadecimal value").arg(name, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return defines;
|
return filteredDefines;
|
||||||
}
|
}
|
||||||
|
|
12
project.h
12
project.h
|
@ -23,7 +23,9 @@ public:
|
||||||
QMap<int, QString> mapAttributesTableMaster;
|
QMap<int, QString> mapAttributesTableMaster;
|
||||||
QMap<QString, QMap<QString, QString>> mapAttributes;
|
QMap<QString, QMap<QString, QString>> mapAttributes;
|
||||||
QMap<QString, QMap<QString, QString>> mapAttributesMaster;
|
QMap<QString, QMap<QString, QString>> mapAttributesMaster;
|
||||||
|
QStringList *itemNames = NULL;
|
||||||
|
QStringList *flagNames = NULL;
|
||||||
|
QStringList *varNames = NULL;
|
||||||
|
|
||||||
QMap<QString, Map*> *map_cache;
|
QMap<QString, Map*> *map_cache;
|
||||||
Map* loadMap(QString);
|
Map* loadMap(QString);
|
||||||
|
@ -65,14 +67,16 @@ public:
|
||||||
void saveMapGroupsTable();
|
void saveMapGroupsTable();
|
||||||
void saveMapConstantsHeader();
|
void saveMapConstantsHeader();
|
||||||
|
|
||||||
QList<QStringList>* parse(QString text);
|
QList<QStringList>* parseAsm(QString text);
|
||||||
QStringList getSongNames();
|
QStringList getSongNames();
|
||||||
QString getSongName(int);
|
|
||||||
QStringList getLocations();
|
QStringList getLocations();
|
||||||
QStringList getVisibilities();
|
QStringList getVisibilities();
|
||||||
QStringList getWeathers();
|
QStringList getWeathers();
|
||||||
QStringList getMapTypes();
|
QStringList getMapTypes();
|
||||||
QStringList getBattleScenes();
|
QStringList getBattleScenes();
|
||||||
|
void readItemNames();
|
||||||
|
void readFlagNames();
|
||||||
|
void readVarNames();
|
||||||
|
|
||||||
void loadObjectPixmaps(QList<Event*> objects);
|
void loadObjectPixmaps(QList<Event*> objects);
|
||||||
QMap<QString, int> getMapObjGfxConstants();
|
QMap<QString, int> getMapObjGfxConstants();
|
||||||
|
@ -95,6 +99,8 @@ private:
|
||||||
void saveMapHeader(Map*);
|
void saveMapHeader(Map*);
|
||||||
void saveMapAttributesTable();
|
void saveMapAttributesTable();
|
||||||
void updateMapAttributes(Map* map);
|
void updateMapAttributes(Map* map);
|
||||||
|
void readCDefinesSorted(QString, QStringList, QStringList*);
|
||||||
|
void readCDefinesSorted(QString, QStringList, QStringList*, QString, int);
|
||||||
|
|
||||||
void setNewMapHeader(Map* map, int mapIndex);
|
void setNewMapHeader(Map* map, int mapIndex);
|
||||||
void setNewMapAttributes(Map* map);
|
void setNewMapAttributes(Map* map);
|
||||||
|
|
Loading…
Reference in a new issue