Merge branch 'startup' into cs_load.

Fix include in textinputdialog.cpp.
This commit is contained in:
Michal Sciubidlo 2013-02-05 21:23:49 +01:00
commit f7e5ea24f4
20 changed files with 326 additions and 66 deletions

View file

@ -15,7 +15,7 @@ include (OpenMWMacros)
# Version # Version
set (OPENMW_VERSION_MAJOR 0) set (OPENMW_VERSION_MAJOR 0)
set (OPENMW_VERSION_MINOR 20) set (OPENMW_VERSION_MINOR 21)
set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION_RELEASE 0)
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
@ -306,7 +306,7 @@ endif()
# Compiler settings # Compiler settings
if (CMAKE_COMPILER_IS_GNUCC) if (CMAKE_COMPILER_IS_GNUCC)
add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++0x -pedantic) add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++03 -pedantic -Wno-long-long)
# Silence warnings in OGRE headers. Remove once OGRE got fixed! # Silence warnings in OGRE headers. Remove once OGRE got fixed!
add_definitions (-Wno-ignored-qualifiers) add_definitions (-Wno-ignored-qualifiers)
@ -496,7 +496,7 @@ if (WIN32)
# Warnings that aren't enabled normally and don't need to be enabled # Warnings that aren't enabled normally and don't need to be enabled
# They're unneeded and sometimes completely retarded warnings that /Wall enables # They're unneeded and sometimes completely retarded warnings that /Wall enables
# Not going to bother commenting them as they tend to warn on every standard library files # Not going to bother commenting them as they tend to warn on every standard library files
4061 4263 4264 4266 4350 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 4061 4263 4264 4266 4350 4371 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946
# Warnings that are thrown on standard libraries and not OpenMW # Warnings that are thrown on standard libraries and not OpenMW
4347 # Non-template function with same name and parameter count as template function 4347 # Non-template function with same name and parameter count as template function
@ -507,6 +507,11 @@ if (WIN32)
4986 # Undocumented warning that occurs in the crtdbg.h file 4986 # Undocumented warning that occurs in the crtdbg.h file
4996 # Function was declared deprecated 4996 # Function was declared deprecated
# cause by ogre extensivly
4193 # #pragma warning(pop) : no matching '#pragma warning(push)'
4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY'
4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY'
# OpenMW specific warnings # OpenMW specific warnings
4099 # Type mismatch, declared class or struct is defined with other type 4099 # Type mismatch, declared class or struct is defined with other type
4100 # Unreferenced formal parameter (-Wunused-parameter) 4100 # Unreferenced formal parameter (-Wunused-parameter)

View file

@ -5,7 +5,7 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QValidator> #include <QValidator>
#include "lineedit.hpp" #include <components/fileorderlist/utils/lineedit.hpp>
#include "textinputdialog.hpp" #include "textinputdialog.hpp"

View file

@ -1,46 +1,77 @@
set (OPENCS_SRC set (OPENCS_SRC main.cpp)
main.cpp editor.cpp
model/doc/documentmanager.cpp model/doc/document.cpp opencs_units (. editor)
model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp
model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp
model/world/columnbase.cpp
model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp opencs_units (model/doc
model/tools/mandatoryid.cpp model/tools/reportmodel.cpp document
view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp
view/doc/subview.cpp view/doc/opendialog.cpp
view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp
view/world/dialoguesubview.cpp
view/tools/reportsubview.cpp view/tools/subviews.cpp
) )
set (OPENCS_HDR opencs_units_noqt (model/doc
editor.hpp documentmanager
model/doc/documentmanager.hpp model/doc/document.hpp model/doc/state.hpp
model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp
model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp
model/world/commands.hpp model/world/columnbase.hpp
model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp
model/tools/mandatoryid.hpp model/tools/reportmodel.hpp
view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp
view/doc/subview.hpp view/doc/subviewfactoryimp.hpp view/doc/opendialog.hpp
view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp
view/world/dialoguesubview.hpp
view/tools/reportsubview.hpp view/tools/subviews.hpp
) )
opencs_hdrs_noqt (model/doc
state
)
opencs_units (model/world
idtable idtableproxymodel
)
opencs_units_noqt (model/world
universalid data record idcollection commands columnbase
)
opencs_hdrs_noqt (model/world
columns
)
opencs_units (model/tools
tools operation reportmodel
)
opencs_units_noqt (model/tools
stage verifier mandatoryid
)
opencs_units (view/doc
viewmanager view operations operation subview startup opendialog
)
opencs_units_noqt (view/doc
subviewfactory
)
opencs_hdrs_noqt (view/doc
subviewfactoryimp
)
opencs_units (view/world
table tablesubview
)
opencs_units_noqt (view/world
dialoguesubview util subviews
)
opencs_units (view/tools
reportsubview
)
opencs_units_noqt (view/tools
subviews
)
set (OPENCS_US set (OPENCS_US
) )
@ -57,7 +88,7 @@ find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED)
include(${QT_USE_FILE}) include(${QT_USE_FILE})
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR}) qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})

View file

@ -11,19 +11,49 @@
CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0)
{ {
connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ()));
connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ()));
connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ()));
} }
void CS::Editor::createDocument() void CS::Editor::createDocument()
{ {
mStartup.hide();
/// \todo open the ESX picker instead
std::ostringstream stream; std::ostringstream stream;
stream << "NewDocument" << (++mNewDocumentIndex); stream << "NewDocument" << (++mNewDocumentIndex);
CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); std::vector<boost::filesystem::path> files;
files.push_back (stream.str());
CSMDoc::Document *document = mDocumentManager.addDocument (files, true);
mViewManager.addView (document);
}
void CS::Editor::loadDocument()
{
mStartup.hide();
/// \todo open the ESX picker instead
/// \todo remove the manual record creation and load the ESX files instead
std::ostringstream stream;
stream << "Document" << (++mNewDocumentIndex);
std::vector<boost::filesystem::path> files;
files.push_back (stream.str());
CSMDoc::Document *document = mDocumentManager.addDocument (files, false);
static const char *sGlobals[] = static const char *sGlobals[] =
{ {
"Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0
}; };
for (int i=0; sGlobals[i]; ++i) for (int i=0; sGlobals[i]; ++i)
@ -42,8 +72,7 @@ void CS::Editor::createDocument()
int CS::Editor::run() int CS::Editor::run()
{ {
/// \todo Instead of creating an empty document, open a small welcome dialogue window with buttons for new/load/recent projects mStartup.show();
createDocument();
return QApplication::exec(); return QApplication::exec();
} }

View file

@ -4,7 +4,9 @@
#include <QObject> #include <QObject>
#include "model/doc/documentmanager.hpp" #include "model/doc/documentmanager.hpp"
#include "view/doc/viewmanager.hpp" #include "view/doc/viewmanager.hpp"
#include "view/doc/startup.hpp"
namespace CS namespace CS
{ {
@ -16,6 +18,7 @@ namespace CS
CSMDoc::DocumentManager mDocumentManager; CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager; CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup;
// not implemented // not implemented
Editor (const Editor&); Editor (const Editor&);
@ -28,9 +31,11 @@ namespace CS
int run(); int run();
///< \return error status ///< \return error status
public slots: private slots:
void createDocument(); void createDocument();
void loadDocument();
}; };
} }

View file

@ -1,10 +1,58 @@
#include "document.hpp" #include "document.hpp"
CSMDoc::Document::Document (const std::string& name) #include <iostream>
void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin,
const std::vector<boost::filesystem::path>::const_iterator& end)
{
for (std::vector<boost::filesystem::path>::const_iterator iter (begin); iter!=end; ++iter)
std::cout << "pretending to load " << iter->string() << std::endl;
/// \todo load content files
}
void CSMDoc::Document::createBase()
{
static const char *sGlobals[] =
{
"Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0
};
for (int i=0; sGlobals[i]; ++i)
{
ESM::Global record;
record.mId = sGlobals[i];
record.mValue = i==0 ? 1 : 0;
record.mType = ESM::VT_Float;
getData().getGlobals().add (record);
}
}
CSMDoc::Document::Document (const std::vector<boost::filesystem::path>& files, bool new_)
: mTools (mData) : mTools (mData)
{ {
mName = name; ///< \todo replace with ESX list if (files.empty())
throw std::runtime_error ("Empty content file sequence");
/// \todo adjust last file name:
/// \li make sure it is located in the data-local directory (adjust path if necessary)
/// \li make sure the extension matches the new scheme (change it if necesarry)
mName = files.back().filename().string();
if (files.size()>1 || !new_)
{
std::vector<boost::filesystem::path>::const_iterator end = files.end();
if (new_)
--end;
load (files.begin(), end);
}
if (new_ && files.size()==1)
createBase();
connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));

View file

@ -3,6 +3,8 @@
#include <string> #include <string>
#include <boost/filesystem/path.hpp>
#include <QUndoStack> #include <QUndoStack>
#include <QObject> #include <QObject>
#include <QTimer> #include <QTimer>
@ -38,10 +40,14 @@ namespace CSMDoc
Document (const Document&); Document (const Document&);
Document& operator= (const Document&); Document& operator= (const Document&);
void load (const std::vector<boost::filesystem::path>::const_iterator& begin,
const std::vector<boost::filesystem::path>::const_iterator& end);
void createBase();
public: public:
Document (const std::string& name); Document (const std::vector<boost::filesystem::path>& files, bool new_);
///< \todo replace name with ESX list
QUndoStack& getUndoStack(); QUndoStack& getUndoStack();

View file

@ -14,9 +14,10 @@ CSMDoc::DocumentManager::~DocumentManager()
delete *iter; delete *iter;
} }
CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::string& name) CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files,
bool new_)
{ {
Document *document = new Document (name); Document *document = new Document (files, new_);
mDocuments.push_back (document); mDocuments.push_back (document);

View file

@ -4,6 +4,8 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <boost/filesystem/path.hpp>
namespace CSMDoc namespace CSMDoc
{ {
class Document; class Document;
@ -21,8 +23,11 @@ namespace CSMDoc
~DocumentManager(); ~DocumentManager();
Document *addDocument (const std::string& name); Document *addDocument (const std::vector<boost::filesystem::path>& files, bool new_);
///< The ownership of the returned document is not transferred to the caller. ///< The ownership of the returned document is not transferred to the caller.
///
/// \param new_ Do not load the last content file in \a files and instead create in an
/// appropriate way.
bool removeDocument (Document *document); bool removeDocument (Document *document);
///< \return last document removed? ///< \return last document removed?

View file

@ -0,0 +1,20 @@
#include "startup.hpp"
#include <QPushButton>
#include <QHBoxLayout>
CSVDoc::StartupDialogue::StartupDialogue()
{
QHBoxLayout *layout = new QHBoxLayout (this);
QPushButton *createDocument = new QPushButton ("new", this);
connect (createDocument, SIGNAL (clicked()), this, SIGNAL (createDocument()));
layout->addWidget (createDocument);
QPushButton *loadDocument = new QPushButton ("load", this);
connect (loadDocument, SIGNAL (clicked()), this, SIGNAL (loadDocument()));
layout->addWidget (loadDocument);
setLayout (layout);
}

View file

@ -0,0 +1,24 @@
#ifndef CSV_DOC_STARTUP_H
#define CSV_DOC_STARTUP_H
#include <QWidget>
namespace CSVDoc
{
class StartupDialogue : public QWidget
{
Q_OBJECT
public:
StartupDialogue();
signals:
void createDocument();
void loadDocument();
};
}
#endif

View file

@ -37,6 +37,10 @@ void CSVDoc::View::setupFileMenu()
connect (mOpen, SIGNAL (triggered()), this, SLOT (open())); connect (mOpen, SIGNAL (triggered()), this, SLOT (open()));
file->addAction (mOpen); file->addAction (mOpen);
QAction *open = new QAction (tr ("Open"), this);
connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest()));
file->addAction (open);
mSave = new QAction (tr ("&Save"), this); mSave = new QAction (tr ("&Save"), this);
connect (mSave, SIGNAL (triggered()), this, SLOT (save())); connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
file->addAction (mSave); file->addAction (mSave);

View file

@ -87,6 +87,8 @@ namespace CSVDoc
void newDocumentRequest(); void newDocumentRequest();
void loadDocumentRequest();
public slots: public slots:
void addSubView (const CSMWorld::UniversalId& id); void addSubView (const CSMWorld::UniversalId& id);

View file

@ -57,6 +57,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
view->show(); view->show();
connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest())); connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest()));
connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
updateIndices(); updateIndices();

View file

@ -46,6 +46,8 @@ namespace CSVDoc
void newDocumentRequest(); void newDocumentRequest();
void loadDocumentRequest();
private slots: private slots:
void documentStateChanged (int state, CSMDoc::Document *document); void documentStateChanged (int state, CSMDoc::Document *document);

View file

@ -32,7 +32,7 @@ namespace MWWorld
} }
assert(it != invStore.end()); assert(it != invStore.end());
std::string npcRace = actor.get<ESM::NPC>()->mBase->mRace; std::string npcRace = actor.get<ESM::NPC>()->mBase->mRace;
// equip the item in the first free slot // equip the item in the first free slot
@ -43,7 +43,7 @@ namespace MWWorld
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part) // Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
if(npcRace == "argonian" || npcRace == "khajiit") if(npcRace == "argonian" || npcRace == "khajiit")
{ {
if(*slot == MWWorld::InventoryStore::Slot_Helmet){ if(*slot == MWWorld::InventoryStore::Slot_Helmet){
std::vector<ESM::PartReference> parts; std::vector<ESM::PartReference> parts;
if(it.getType() == MWWorld::ContainerStore::Type_Clothing) if(it.getType() == MWWorld::ContainerStore::Type_Clothing)
@ -54,22 +54,22 @@ namespace MWWorld
bool allow = true; bool allow = true;
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr) for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{ {
if((*itr).mPart == ESM::PartReferenceType::PRT_Head) if((*itr).mPart == ESM::PRT_Head)
{ {
if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() )
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}", std::vector<std::string>()); MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}", std::vector<std::string>());
allow = false; allow = false;
break; break;
} }
} }
if(!allow) if(!allow)
break; break;
} }
if (*slot == MWWorld::InventoryStore::Slot_Boots) if (*slot == MWWorld::InventoryStore::Slot_Boots)
{ {
// Only notify the player, not npcs // Only notify the player, not npcs
if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() )
{ {

View file

@ -45,3 +45,51 @@ get_filename_component(filename ${f} NAME)
configure_file(${source_dir}/${f} ${destination_dir}/${filename} COPYONLY) configure_file(${source_dir}/${f} ${destination_dir}/${filename} COPYONLY)
endforeach (f) endforeach (f)
endmacro (copy_all_files) endmacro (copy_all_files)
macro (add_file project type file)
list (APPEND ${project}${type} ${file})
endmacro (add_file)
macro (add_unit project dir unit)
add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp")
add_file (${project} _SRC ${comp} "${dir}/${unit}.cpp")
endmacro (add_unit)
macro (add_qt_unit project dir unit)
add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp")
add_file (${project} _HDR_QT ${comp} "${dir}/${unit}.hpp")
add_file (${project} _SRC ${comp} "${dir}/${unit}.cpp")
endmacro (add_qt_unit)
macro (add_hdr project dir unit)
add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp")
endmacro (add_hdr)
macro (add_qt_hdr project dir unit)
add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp")
add_file (${project} _HDR_QT ${comp} "${dir}/${unit}.hpp")
endmacro (add_qt_hdr)
macro (opencs_units dir)
foreach (u ${ARGN})
add_qt_unit (OPENCS ${dir} ${u})
endforeach (u)
endmacro (opencs_units)
macro (opencs_units_noqt dir)
foreach (u ${ARGN})
add_unit (OPENCS ${dir} ${u})
endforeach (u)
endmacro (opencs_units_noqt)
macro (opencs_hdrs dir)
foreach (u ${ARGN})
add_qt_hdr (OPENCS ${dir} ${u})
endforeach (u)
endmacro (opencs_hdrs)
macro (opencs_hdrs_noqt dir)
foreach (u ${ARGN})
add_hdr (OPENCS ${dir} ${u})
endforeach (u)
endmacro (opencs_hdrs_noqt)

View file

@ -91,7 +91,7 @@ public:
std::string searchable = normalize_path (proper.begin () + prefix, proper.end ()); std::string searchable = normalize_path (proper.begin () + prefix, proper.end ());
mIndex.insert (std::make_pair (std::move (searchable), std::move (proper))); mIndex.insert (std::make_pair (searchable, proper));
} }
} }

View file

@ -3,11 +3,8 @@
#include <stdexcept> #include <stdexcept>
#include <cassert> #include <cassert>
#ifndef __clang__
#include <cstdint> #include <libs/platform/stdint.h>
#else
#include <tr1/cstdint>
#endif
namespace { namespace {
@ -29,7 +26,7 @@ public:
mBufferOrigin = 0; mBufferOrigin = 0;
mBufferExtent = 0; mBufferExtent = 0;
} }
size_t read(void* buf, size_t count) size_t read(void* buf, size_t count)
{ {

View file

@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind
OpenMW is an attempt at recreating the engine for the popular role-playing game OpenMW is an attempt at recreating the engine for the popular role-playing game
Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
Version: 0.20.0 Version: 0.21.0
License: GPL (see GPL3.txt for more information) License: GPL (see GPL3.txt for more information)
Website: http://www.openmw.org Website: http://www.openmw.org
@ -94,6 +94,38 @@ Allowed options:
CHANGELOG CHANGELOG
0.21.0
Bug #253: Dialogs don't work for Russian version of Morrowind
Bug #267: Activating creatures without dialogue can still activate the dialogue GUI
Bug #354: True flickering lights
Bug #386: The main menu's first entry is wrong (in french)
Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations
Bug #495: Activation Range
Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned
Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available
Bug #500: Disposition for most NPCs is 0/100
Bug #501: Getdisposition command wrongly returns base disposition
Bug #506: Journal UI doesn't update anymore
Bug #507: EnableRestMenu is not a valid command - change it to EnableRest
Bug #508: Crash in Ald Daedroth Shrine
Bug #517: Wrong price calculation when untrading an item
Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin
Bug #524: Beast races are able to wear shoes
Bug #527: Background music fails to play
Bug #533: The arch at Gnisis entrance is not displayed
Bug #536: The same entry can be added multiple times to the journal
Bug #539: Race selection is broken
Feature #39: Video Playback
Feature #151: ^-escape sequences in text output
Feature #392: Add AI related script functions
Feature #456: Determine required ini fallback values and adjust the ini importer accordingly
Feature #460: Experimental DirArchives improvements
Feature #540: Execute scripts of objects in containers/inventories in active cells
Task #401: Review GMST fixing
Task #453: Unify case smashing/folding
Task #512: Rewrite utf8 component
0.20.0 0.20.0
Bug #366: Changing the player's race during character creation does not change the look of the player character Bug #366: Changing the player's race during character creation does not change the look of the player character