33 statusBar()->showMessage(tr(
"Ready"));
37 setWindowTitle(tr(
"Crossfire Resource Editor"));
64 QMainWindow::closeEvent(event);
86 myOpenFormulae->setStatusTip(tr(
"List all defined alchemy recipes."));
90 myOpenResources->setStatusTip(tr(
"List all defined elements, except experience table."));
94 myOpenFaces->setStatusTip(tr(
"List all defined faces."));
98 myOpenMaps->setStatusTip(tr(
"List all maps, with their region."));
102 myOpenQuests->setStatusTip(tr(
"List all defined quests."));
106 myOpenMessages->setStatusTip(tr(
"List all NPC dialogs in files."));
126 mySaveQuests->setStatusTip(tr(
"Save all modified quests to disk."));
130 mySaveMessages->setStatusTip(tr(
"Save all modified NPC dialogs."));
134 myReportDuplicate->setStatusTip(tr(
"Show faces and animations which are used by multiple archetypes, or not used."));
138 myReportSpellDamage->setStatusTip(tr(
"Display spell damage by level (bullet spells only for now)"));
142 myReportAlchemy->setStatusTip(tr(
"Display alchemy formulae, in a table."));
146 myReportSpells->setStatusTip(tr(
"Display all spells, in a table."));
150 myReportPlayer->setStatusTip(tr(
"Compute statistics related to player vs monster combat."));
155 myReportSummon =
new QAction(tr(
"Summoned pets statistics"),
this);
156 myReportSummon->setStatusTip(tr(
"Display wc, hp, speed and other statistics for summoned pets."));
159 myReportShops =
new QAction(tr(
"Shop specialization"),
this);
160 myReportShops->setStatusTip(tr(
"Display the list of shops and their specialization for items."));
165 myReportQuests =
new QAction(tr(
"Quest solved by players"),
this);
166 myReportQuests->setStatusTip(tr(
"Display quests the players have solved."));
171 myToolSmooth =
new QAction(tr(
"Generate smooth face base"),
this);
172 myToolSmooth->setStatusTip(tr(
"Generate the basic smoothed picture for a face."));
175 myToolHPBar =
new QAction(tr(
"Generate HP bar"),
this);
176 myToolHPBar->setStatusTip(tr(
"Generate faces for a HP bar."));
184 myClearMapCache->setStatusTip(tr(
"Force a refresh of all map information at next start."));
207 QAction* exit =
myOpenMenu->addAction(tr(
"&Exit"));
208 exit->setStatusTip(tr(
"Close the application."));
209 connect(exit, SIGNAL(triggered()),
this, SLOT(close()));
216 QMenu* reportMenu = menuBar()->addMenu(
"&Reports");
226 QMenu* toolsMenu = menuBar()->addMenu(
"&Tools");
241 myArea->addSubWindow(resources);
298 myArea->addSubWindow(experience);
335 statusBar()->showMessage(tr(
"Finished browsing maps."), 5000);
361 QHash<QString, QStringList> faces, anims;
371 faces[QString::fromLatin1(arch->
clone.
face->
name)].append(QString(arch->
name) +
" (arch)");
375 faces[QString(key)].append(QString(arch->
name) +
" (arch)");
384 anims[QString(key)].append(QString(arch->
name) +
" (arch)");
392 foreach(QString name, allAnims)
399 if (!done.contains(QString::fromLatin1(anim->
faces[i]->
name)))
401 faces[QString::fromLatin1(anim->
faces[i]->
name)].append(QString(anim->
name) +
" (animation)");
402 done.append(QString::fromLatin1(anim->
faces[i]->
name));
412 for (art = list->
items; art != NULL; art = art->
next)
420 faces[QString(key)].append(QString(art->
item->
name) +
" (art)");
429 anims[QString(key)].append(QString(art->
item->
name) +
" (arch)");
435 QString report(
"<p><strong>Warning:</strong> this list doesn't take into account faces for all artifacts, especially the 'animation_suffix' ones. Also, faces and archetypes defined in maps will not be taken into account in this list.</p><h1>Faces used multiple times:</h1><ul>");
437 QStringList keys = faces.keys();
439 foreach(QString name, keys)
441 if (faces[name].size() <= 1 || name.compare(
"blank.111") == 0)
445 report +=
"<li>" + name +
": ";
446 report += faces[name].join(
", ");
452 report +=
"<h1>Unused faces:</h1><ul>";
455 if (faces[face].size() > 0)
457 report +=
"<li>" + face +
"</li>";
461 report +=
"<h1>Animations used multiple times:</h1><ul>";
464 foreach(QString name, keys)
466 if (anims[name].size() <= 1)
470 report +=
"<li>" + name +
": ";
471 report += anims[name].join(
", ");
476 report +=
"<h1>Unused animations:</h1><ul>";
479 if (anims[anim].size() > 0 || anim ==
"###none")
481 report +=
"<li>" + anim +
"</li>";
492 QList<QStringList> damage;
509 dam.append(tr(
"%1 [%2]").arg(dm).arg(cost));
518 QString report(
"<table><thead><tr><th>level</th>");
520 for (
int i = 0; i < spell.size(); i++)
522 report +=
"<th>" + spell[i] +
"</th>";
525 report +=
"</tr></thead><tbody>";
529 report +=
"<tr><td>" + QString::number(l) +
"</td>";
530 for (
int s = 0; s < spell.size(); s++)
531 report +=
"<td>" + damage[s][l] +
"</td>";
535 report +=
"</tbody></table>";
545 QHash<int, QStringList> recipes;
550 for (
int ing = 1; ; ing++)
556 for (recipe = list->
items; recipe; recipe = recipe->
next)
558 if (skill == recipe->
skill)
567 if (strcmp(recipe->
title,
"NONE") == 0)
579 QStringList ingredients;
582 ingredients.append(ingred->name);
585 recipes[recipe->
diff].append(QString(
"<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td></tr>").arg(name).arg(recipe->
diff).arg(recipe->
ingred_count).arg(recipe->
exp).arg(ingredients.join(
", ")));
594 QString report = QString(
"<h2>%1 (%2 recipes)</h2><table><thead><tr><th>product</th><th>difficulty</th><th>ingredients count</th><th>experience</th><th>Ingredients</th>").arg(skill).arg(count);
595 report +=
"</tr></thead><tbody>";
597 QList<int> difficulties = recipes.keys();
599 foreach(
int difficulty, difficulties)
601 QStringList line = recipes[difficulty];
603 report += line.join(
"\n");
606 report +=
"</tbody></table>";
616 for (; arch; arch = arch->
next)
624 QString report(
"<h1>Alchemy formulae</h1>");
626 foreach(
const QString skill, skills)
639 QString report = QString(
"<h2>%1</h2><table><thead><tr><th>Spell</th><th>Level</th>").arg(skill);
640 report +=
"</tr></thead><tbody>";
642 QHash<int, QStringList> spells;
658 QList<int>
levels = spells.keys();
660 foreach(
int level, levels)
662 report += spells[level].join(
"\n");
665 report +=
"</tbody></table>";
675 for (; arch; arch = arch->
next)
683 QString report(
"<h1>Spell list</h1>");
685 foreach(
const QString skill, skills)
705 int limit = 50, result = 1;
707 memset(&pl, 0,
sizeof(
player));
714 obfirst->
level = level;
715 obfirst->
contr = &pl;
718 obskill->
level = level;
739 qDebug() <<
"second removed??";
742 while (limit-- > 0 && obfirst->
stats.
hp >= 0 && obsecond->
stats.
hp >= 0)
832 level = (max + first) / 2;
843 if (ret > (count / 2) && (level < half))
874 return "<td colspan=\"2\">-</td>";
875 return "<td>" + QString::number(min) +
"</td><td>" + ((half != 0) ? QString::number(half) :
"") +
"</td>";
886 QString line =
"<tr>";
888 line +=
"<td>" + QString(monster->
clone.
name) +
"</td>";
889 line +=
"<td>" + QString::number(monster->
clone.
level) +
"</td>";
890 line +=
"<td>" + QString::number(monster->
clone.
speed) +
"</td>";
891 line +=
"<td>" + QString::number(monster->
clone.
stats.
wc) +
"</td>";
892 line +=
"<td>" + QString::number(monster->
clone.
stats.
dam) +
"</td>";
893 line +=
"<td>" + QString::number(monster->
clone.
stats.
ac) +
"</td>";
894 line +=
"<td>" + QString::number(monster->
clone.
stats.
hp) +
"</td>";
895 line +=
"<td>" + QString::number(monster->
clone.
stats.
Con) +
"</td>";
912 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
915 QMap<QString, archetype*> monsters;
916 QList<archetype*> skills;
919 for (; arch; arch = arch->
next)
923 QString name(QString(arch->
clone.
name).toLower());
924 if (monsters.contains(name))
929 name = QString(arch->
clone.
name).toLower() +
"_" + QString::number(suffix);
931 }
while (monsters.contains(name));
934 monsters[name] = arch;
938 if (strcmp(arch->
name,
"skill_missile_weapon") == 0 || strcmp(arch->
name,
"skill_throwing") == 0)
944 names = monsters.keys();
947 QString report(tr(
"<h1>Player vs monsters</h1><p><strong>fv</strong> is the level at which the first victory happened, <strong>hv</strong> is the level at which at least 50% of fights were victorious.</p>\n")), line;
948 report +=
"<table border=\"1\"><tbody>\n";
950 report +=
"<th rowspan=\"2\">Monster</th>";
951 report +=
"<th rowspan=\"2\">level</th>";
952 report +=
"<th rowspan=\"2\">speed</th>";
953 report +=
"<th rowspan=\"2\">wc</th>";
954 report +=
"<th rowspan=\"2\">dam</th>";
955 report +=
"<th rowspan=\"2\">ac</th>";
956 report +=
"<th rowspan=\"2\">hp</th>";
957 report +=
"<th rowspan=\"2\">regen</th>";
962 report +=
"<th colspan=\"2\">" + QString(skill->
clone.
name) +
"</th>";
963 line +=
"<th>fv</th><th>hv</th>";
965 report +=
"</tr>\n" + line +
"</tr>\n";
968 foreach(
const QString name, names)
975 report +=
"</tbody></table>\n";
978 QApplication::restoreOverrideCursor();
985 int level, wc_adj = 0;
987 const object* spell = &summon->
clone;
995 QString ac(
"<tr><td>ac</td>");
996 QString hp(
"<tr><td>hp</td>");
997 QString dam(
"<tr><td>dam</td>");
998 QString speed(
"<tr><td>speed</td>");
999 QString wc(
"<tr><td>wc</td>");
1000 int ihp, idam, iwc, diff;
1003 for (level = 1; level < 120; level += 10)
1005 if (level < spell->level)
1010 speed +=
"<td></td>";
1015 diff = level - spell->
level;
1022 iwc -= (diff / wc_adj);
1024 ac +=
"<td>" + QString::number(other->
stats.
ac) +
"</td>";
1025 hp +=
"<td>" + QString::number(ihp) +
"</td>";
1026 dam +=
"<td>" + QString::number(idam) +
"</td>";
1027 speed +=
"<td>" + QString::number(fspeed) +
"</td>";
1028 wc +=
"<td>" + QString::number(iwc) +
"</td>";
1031 report +=
"<tr><td colspan=\"13\"><strong>" + name +
"</strong></td></tr>\n";
1033 report += ac +
"</tr>\n" + hp +
"</tr>\n" + dam +
"</tr>\n" + speed +
"</tr>\n" + wc +
"</tr>\n\n";
1040 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1044 QString report(tr(
"<h1>Summoned pet statistics</h1>\n")), line;
1045 report +=
"<table border=\"1\">\n<thead>\n";
1047 report +=
"<th rowspan=\"2\">Spell</th>";
1048 report +=
"<th colspan=\"12\">Level</th>";
1049 report +=
"</tr>\n";
1052 for (level = 1; level < 120; level += 10)
1054 report +=
"<th>" + QString::number(level) +
"</th>";
1056 report +=
"</tr>\n</thead>\n<tbody>\n";
1058 QMap<QString, QString> spells;
1064 if (summon->clone.other_arch != NULL)
1066 spells[summon->clone.name] =
reportSummon(summon, &summon->clone.other_arch->clone, QString(summon->clone.name));
1073 if (god->clone.type !=
GOD)
1076 QString name(QString(summon->clone.name) +
" (" + QString(god->name) +
")");
1085 QStringList keys = spells.keys();
1087 foreach(QString key, keys)
1089 report += spells[key];
1092 report +=
"</tbody>\n</table>\n";
1095 QApplication::restoreOverrideCursor();
1101 QString report(
"<h2>" + title +
"</h2>");
1102 report +=
"<table border=\"1\">\n<thead>\n";
1104 report +=
"<th>Shop</th>";
1105 report +=
"<th>Greed</th>";
1106 report +=
"<th>Race</th>";
1107 report +=
"<th>Min</th>";
1108 report +=
"<th>Max</th>";
1109 foreach (QString item, types)
1111 report +=
"<th>" + item +
"</th>";
1112 items.removeAll(item);
1114 report +=
"</tr>\n</thead><tbody>";
1126 line +=
"<td>" + map->
name() +
" " + map->
path() +
"</td>";
1127 line +=
"<td>" + QString::number(map->
shopGreed()) +
"</td>";
1128 line +=
"<td>" + map->
shopRace() +
"</td>";
1129 line +=
"<td>" + (map->
shopMin() != 0 ? QString::number(map->
shopMin()) :
"") +
"</td>";
1130 line +=
"<td>" + (map->
shopMax() != 0 ? QString::number(map->
shopMax()) :
"") +
"</td>";
1132 foreach(
const QString item, types)
1137 line +=
"<td></td>";
1139 line +=
"<td>" + QString::number(map->
shopItems()[
"*"]) +
"</td>";
1143 line +=
"<td>" + QString::number(map->
shopItems()[item]) +
"</td>";
1151 report +=
"</tbody></table>";
1157 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1159 QString report(tr(
"<h1>Shop information</h1>\n"));
1165 QStringList add = map->
shopItems().keys();
1166 foreach(
const QString item, add)
1168 if (!items.contains(item))
1176 part <<
"weapon" <<
"weapon improver" <<
"bow" <<
"arrow";
1180 part <<
"armour" <<
"armour improver" <<
"boots" <<
"bracers" <<
"cloak" <<
"girdle" <<
"gloves" <<
"helmet" <<
"shield";
1184 part <<
"amulet" <<
"potion" <<
"power_crystal" <<
"ring" <<
"rod" <<
"scroll" <<
"skillscroll" <<
"spellbook" <<
"wand";
1188 part <<
"container" <<
"food" <<
"key" <<
"lamp" <<
"skill tool" <<
"special key";
1191 if (!items.isEmpty())
1199 QApplication::restoreOverrideCursor();
1203 void readDirectory(
const QString& path, QHash<QString, QHash<QString, bool> >& states)
1206 QStringList subdirs = dir.entryList(QStringList(
"*"), QDir::Dirs | QDir::NoDotAndDotDot);
1207 foreach(QString subdir, subdirs)
1212 QStringList
quests = dir.entryList(QStringList(
"*.quest"), QDir::Files);
1213 foreach(QString file, quests)
1215 qDebug() <<
"read quest:" << path << file;
1216 QString name = file.left(file.length() - 6);
1217 QFile read(path + QDir::separator() + file);
1218 read.open(QFile::ReadOnly);
1219 QTextStream stream(&read);
1222 while (!(line = stream.readLine(0)).isNull())
1224 if (line.startsWith(
"quest "))
1232 if (line ==
"end_quest")
1234 states[code][name] = completed;
1238 if (line.startsWith(
"state "))
1240 if (line ==
"completed 1")
1248 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1250 QHash<QString, QHash<QString, bool> > states;
1252 directory += QDir::separator();
1259 codes.append(quest->
code());
1262 QString report(
"<html><body>\n<h1>Quests</h1>\n");
1264 QStringList keys = states.keys();
1267 foreach(QString key, keys)
1269 codes.removeAll(key);
1271 report +=
"<h2>Quest: " + (quest != NULL ? quest->
title() : (key +
" ???")) +
"</h2>\n";
1273 QHash<QString, bool> done = states[key];
1274 QStringList players = done.keys();
1278 foreach(QString
player, players)
1285 report +=
"<strong>" + player +
"</strong>";
1293 report +=
"<p>" + tr(
"%1 completed out of %2 (%3%)").arg(completed).arg(players.size()).arg(completed * 100 / players.size()) +
"</p>\n";
1296 if (codes.length() > 0)
1300 report +=
"<h2>Quests never done</h2>\n<p>\n";
1301 foreach(QString code, codes)
1306 report += (quest != NULL ? quest->
title() : (code +
" ???"));
1311 report +=
"</body>\n</html>\n";
1314 QApplication::restoreOverrideCursor();
1338 QMessageBox confirm;
1339 confirm.setWindowTitle(tr(
"Crossfire Resource Editor"));
1340 confirm.setText(
"Really clear map cache?");
1341 confirm.setInformativeText(
"This will force cache rebuild at next application start.");
1342 confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
1343 confirm.setDefaultButton(QMessageBox::No);
1344 confirm.setIcon(QMessageBox::Question);
1345 if (confirm.exec() == QMessageBox::Yes)
archetype * find_archetype(const char *name)
int move_player(object *op, int dir)
QAction * myReportDuplicate
QAction * myReportSpellDamage
mapstruct * get_empty_map(int sizex, int sizey)
QAction * myOpenAnimations
void do_some_living(object *op)
const QString & code() const
const animations_struct * animation(const QString &name) const
int attack_ob(object *op, object *hitter)
struct artifactstruct * items
const char * object_get_value(const object *op, const char *const key)
static QString buildShopReport(const QString &title, const QStringList &types, const QList< CREMapInformation * > &maps, QStringList &items)
uint8_t duration_modifier
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
static QString reportSummon(const archetype *summon, const object *other, QString name)
int SP_level_dam_adjust(const object *caster, const object *spob)
#define object_was_destroyed(op, old_tag)
static QString monsterTable(archetype *monster, QList< archetype * > skills)
static QString spellsTable(const QString &skill)
void onToolCombatSimulator()
QStringList allAnimations() const
char savebed_map[MAX_BUF]
QAction * myOpenTreasures
void closeEvent(QCloseEvent *event)
QAction * myOpenRandomMaps
void object_free_drop_inventory(object *ob)
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
const QString & title() const
#define FREE_OBJ_FREE_INVENTORY
ResourcesManager * myResourcesManager
void doResourceWindow(DisplayMode mode)
Quest * findByCode(const QString &code)
struct artifactliststruct * next
object * create_archetype(const char *name)
object * object_insert_in_ob(object *op, object *where)
QAction * myOpenArtifacts
MessageManager * myMessageManager
QLabel * myMapBrowseStatus
struct linked_char * next
struct recipestruct recipe
QuestManager * myQuestManager
QAction * myOpenResources
QAction * myOpenExperience
QAction * myOpenArchetypes
EXTERN Animations * animations
QAction * myClearMapCache
static int monsterFight(archetype *monster, archetype *skill, int level)
#define QUERY_FLAG(xyz, p)
QAction * myToolCombatSimulator
EXTERN artifactlist * first_artifactlist
object * object_create_arch(archetype *at)
QAction * myReportAlchemy
CREMapInformationManager * myMapManager
void browsingMap(const QString &path)
archetype * determine_holy_arch(const object *god, const char *type)
QList< const Quest * > quests() const
mapstruct * has_been_loaded(const char *name)
void object_free2(object *ob, int flags)
struct recipestruct * next
void delete_map(mapstruct *m)
QStringList faces() const
static quest_definition * quests
void monster_do_living(object *op)
ScriptFileManager * myScriptManager
#define IS_COMBAT_SKILL(num)
static QString alchemyTable(const QString &skill)
void fix_object(object *op)
EXTERN archetype * first_archetype
struct recipestruct * items
recipelist * get_formulalist(int i)
void object_remove(object *op)
struct artifactstruct * next
void onReportSpellDamage()
void readDirectory(const QString &path, QHash< QString, QHash< QString, bool > > &states)