mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 20:23:51 +00:00
Merge remote-tracking branch 'upstream/next' into multiple_esm_esp
This commit is contained in:
commit
64c08eada4
160 changed files with 6854 additions and 2531 deletions
|
@ -15,7 +15,7 @@ include (OpenMWMacros)
|
|||
# Version
|
||||
|
||||
set (OPENMW_VERSION_MAJOR 0)
|
||||
set (OPENMW_VERSION_MINOR 18)
|
||||
set (OPENMW_VERSION_MINOR 19)
|
||||
set (OPENMW_VERSION_RELEASE 0)
|
||||
|
||||
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
|
@ -306,7 +306,7 @@ endif()
|
|||
|
||||
# Compiler settings
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder)
|
||||
add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++0x -pedantic)
|
||||
|
||||
# Silence warnings in OGRE headers. Remove once OGRE got fixed!
|
||||
add_definitions (-Wno-ignored-qualifiers)
|
||||
|
@ -659,7 +659,6 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE)
|
|||
#INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${SYSCONFDIR}" )
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" )
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" )
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.cfg" DESTINATION "${SYSCONFDIR}" )
|
||||
|
||||
# Install resources
|
||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" )
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
set(ESMTOOL
|
||||
esmtool.cpp
|
||||
labels.hpp
|
||||
labels.cpp
|
||||
record.hpp
|
||||
record.cpp
|
||||
)
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include "record.hpp"
|
||||
|
||||
#define ESMTOOL_VERSION 1.1
|
||||
#define ESMTOOL_VERSION 1.2
|
||||
|
||||
// Create a local alias for brevity
|
||||
namespace bpo = boost::program_options;
|
||||
|
@ -57,6 +57,8 @@ struct Arguments
|
|||
std::string encoding;
|
||||
std::string filename;
|
||||
std::string outname;
|
||||
|
||||
std::vector<std::string> types;
|
||||
|
||||
ESMData data;
|
||||
ESM::ESMReader reader;
|
||||
|
@ -70,7 +72,12 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
|||
desc.add_options()
|
||||
("help,h", "print help message.")
|
||||
("version,v", "print version information and quit.")
|
||||
("raw,r", "Show an unformattet list of all records and subrecords.")
|
||||
("raw,r", "Show an unformatted list of all records and subrecords.")
|
||||
// The intention is that this option would interact better
|
||||
// with other modes including clone, dump, and raw.
|
||||
("type,t", bpo::value< std::vector<std::string> >(),
|
||||
"Show only records of this type (four character record code). May "
|
||||
"be specified multiple times. Only affects dump mode.")
|
||||
("quiet,q", "Supress all record information. Useful for speed tests.")
|
||||
("loadcells,C", "Browse through contents of all cells.")
|
||||
|
||||
|
@ -122,6 +129,9 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (variables.count("type") > 0)
|
||||
info.types = variables["type"].as< std::vector<std::string> >();
|
||||
|
||||
info.mode = variables["mode"].as<std::string>();
|
||||
if (!(info.mode == "dump" || info.mode == "clone" || info.mode == "comp"))
|
||||
{
|
||||
|
@ -306,14 +316,23 @@ int load(Arguments& info)
|
|||
uint32_t flags;
|
||||
esm.getRecHeader(flags);
|
||||
|
||||
// Is the user interested in this record type?
|
||||
bool interested = true;
|
||||
if (info.types.size() > 0)
|
||||
{
|
||||
std::vector<std::string>::iterator match;
|
||||
match = std::find(info.types.begin(), info.types.end(),
|
||||
n.toString());
|
||||
if (match == info.types.end()) interested = false;
|
||||
}
|
||||
|
||||
std::string id = esm.getHNOString("NAME");
|
||||
|
||||
if(!quiet)
|
||||
if(!quiet && interested)
|
||||
std::cout << "\nRecord: " << n.toString()
|
||||
<< " '" << id << "'\n";
|
||||
|
||||
EsmTool::RecordBase *record =
|
||||
EsmTool::RecordBase::create(n.val);
|
||||
EsmTool::RecordBase *record = EsmTool::RecordBase::create(n);
|
||||
|
||||
if (record == 0) {
|
||||
if (std::find(skipped.begin(), skipped.end(), n.val) == skipped.end())
|
||||
|
@ -326,18 +345,16 @@ int load(Arguments& info)
|
|||
if (quiet) break;
|
||||
std::cout << " Skipping\n";
|
||||
} else {
|
||||
if (record->getType() == ESM::REC_GMST) {
|
||||
if (record->getType().val == ESM::REC_GMST) {
|
||||
// preset id for GameSetting record
|
||||
record->cast<ESM::GameSetting>()->get().mId = id;
|
||||
}
|
||||
record->setId(id);
|
||||
record->setFlags((int) flags);
|
||||
record->load(esm);
|
||||
if (!quiet) {
|
||||
record->print();
|
||||
}
|
||||
if (!quiet && interested) record->print();
|
||||
|
||||
if (record->getType() == ESM::REC_CELL && loadCells) {
|
||||
if (record->getType().val == ESM::REC_CELL && loadCells) {
|
||||
loadCell(record->cast<ESM::Cell>()->get(), esm, info);
|
||||
}
|
||||
|
||||
|
@ -434,7 +451,7 @@ int clone(Arguments& info)
|
|||
{
|
||||
EsmTool::RecordBase *record = *it;
|
||||
|
||||
name.val = record->getType();
|
||||
name.val = record->getType().val;
|
||||
|
||||
esm.startRecord(name.toString(), record->getFlags());
|
||||
|
||||
|
|
881
apps/esmtool/labels.cpp
Normal file
881
apps/esmtool/labels.cpp
Normal file
|
@ -0,0 +1,881 @@
|
|||
#include "labels.hpp"
|
||||
|
||||
#include <components/esm/loadbody.hpp>
|
||||
#include <components/esm/loadcell.hpp>
|
||||
#include <components/esm/loadcont.hpp>
|
||||
#include <components/esm/loadcrea.hpp>
|
||||
#include <components/esm/loadlevlist.hpp>
|
||||
#include <components/esm/loadligh.hpp>
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
#include <components/esm/loadrace.hpp>
|
||||
#include <components/esm/loadspel.hpp>
|
||||
#include <components/esm/loadweap.hpp>
|
||||
#include <components/esm/aipackage.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
std::string bodyPartLabel(char idx)
|
||||
{
|
||||
const char *bodyPartLabels[] = {
|
||||
"Head",
|
||||
"Hair",
|
||||
"Neck",
|
||||
"Cuirass",
|
||||
"Groin",
|
||||
"Skirt",
|
||||
"Right Hand",
|
||||
"Left Hand",
|
||||
"Right Wrist",
|
||||
"Left Wrist",
|
||||
"Shield",
|
||||
"Right Forearm",
|
||||
"Left Forearm",
|
||||
"Right Upperarm",
|
||||
"Left Upperarm",
|
||||
"Right Foot",
|
||||
"Left Foot",
|
||||
"Right Ankle",
|
||||
"Left Ankle",
|
||||
"Right Knee",
|
||||
"Left Knee",
|
||||
"Right Leg",
|
||||
"Left Leg",
|
||||
"Right Shoulder",
|
||||
"Left Shoulder",
|
||||
"Weapon",
|
||||
"Tail"
|
||||
};
|
||||
|
||||
if ((int)idx >= 0 && (int)(idx) <= 26)
|
||||
return bodyPartLabels[(int)(idx)];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string meshPartLabel(char idx)
|
||||
{
|
||||
const char *meshPartLabels[] = {
|
||||
"Head",
|
||||
"Hair",
|
||||
"Neck",
|
||||
"Chest",
|
||||
"Groin",
|
||||
"Hand",
|
||||
"Wrist",
|
||||
"Forearm",
|
||||
"Upperarm",
|
||||
"Foot",
|
||||
"Ankle",
|
||||
"Knee",
|
||||
"Upper Leg",
|
||||
"Clavicle",
|
||||
"Tail"
|
||||
};
|
||||
|
||||
if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MP_Tail)
|
||||
return meshPartLabels[(int)(idx)];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string meshTypeLabel(char idx)
|
||||
{
|
||||
const char *meshTypeLabels[] = {
|
||||
"Skin",
|
||||
"Clothing",
|
||||
"Armor"
|
||||
};
|
||||
|
||||
if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MT_Armor)
|
||||
return meshTypeLabels[(int)(idx)];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string clothingTypeLabel(int idx)
|
||||
{
|
||||
const char *clothingTypeLabels[] = {
|
||||
"Pants",
|
||||
"Shoes",
|
||||
"Shirt",
|
||||
"Belt",
|
||||
"Robe",
|
||||
"Right Glove",
|
||||
"Left Glove",
|
||||
"Skirt",
|
||||
"Ring",
|
||||
"Amulet"
|
||||
};
|
||||
|
||||
if (idx >= 0 && idx <= 9)
|
||||
return clothingTypeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string armorTypeLabel(int idx)
|
||||
{
|
||||
const char *armorTypeLabels[] = {
|
||||
"Helmet",
|
||||
"Cuirass",
|
||||
"Left Pauldron",
|
||||
"Right Pauldron",
|
||||
"Greaves",
|
||||
"Boots",
|
||||
"Left Gauntlet",
|
||||
"Right Gauntlet",
|
||||
"Shield",
|
||||
"Left Bracer",
|
||||
"Right Bracer"
|
||||
};
|
||||
|
||||
if (idx >= 0 && idx <= 10)
|
||||
return armorTypeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string dialogTypeLabel(int idx)
|
||||
{
|
||||
const char *dialogTypeLabels[] = {
|
||||
"Topic",
|
||||
"Voice",
|
||||
"Greeting",
|
||||
"Persuasion",
|
||||
"Journal"
|
||||
};
|
||||
|
||||
if (idx >= 0 && idx <= 4)
|
||||
return dialogTypeLabels[idx];
|
||||
else if (idx == -1)
|
||||
return "Deleted";
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string questStatusLabel(int idx)
|
||||
{
|
||||
const char *questStatusLabels[] = {
|
||||
"None",
|
||||
"Name",
|
||||
"Finished",
|
||||
"Restart",
|
||||
"Deleted"
|
||||
};
|
||||
|
||||
if (idx >= 0 && idx <= 4)
|
||||
return questStatusLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string creatureTypeLabel(int idx)
|
||||
{
|
||||
const char *creatureTypeLabels[] = {
|
||||
"Creature",
|
||||
"Daedra",
|
||||
"Undead",
|
||||
"Humanoid",
|
||||
};
|
||||
|
||||
if (idx >= 0 && idx <= 3)
|
||||
return creatureTypeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string soundTypeLabel(int idx)
|
||||
{
|
||||
const char *soundTypeLabels[] = {
|
||||
"Left Foot",
|
||||
"Right Foot",
|
||||
"Swim Left",
|
||||
"Swim Right",
|
||||
"Moan",
|
||||
"Roar",
|
||||
"Scream",
|
||||
"Land"
|
||||
};
|
||||
|
||||
if (idx >= 0 && idx <= 7)
|
||||
return soundTypeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string weaponTypeLabel(int idx)
|
||||
{
|
||||
const char *weaponTypeLabels[] = {
|
||||
"Short Blade One Hand",
|
||||
"Long Blade One Hand",
|
||||
"Long Blade Two Hand",
|
||||
"Blunt One Hand",
|
||||
"Blunt Two Close",
|
||||
"Blunt Two Wide",
|
||||
"Spear Two Wide",
|
||||
"Axe One Hand",
|
||||
"Axe Two Hand",
|
||||
"Marksman Bow",
|
||||
"Marksman Crossbow",
|
||||
"Marksman Thrown",
|
||||
"Arrow",
|
||||
"Bolt"
|
||||
};
|
||||
|
||||
if (idx >= 0 && idx <= 13)
|
||||
return weaponTypeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string aiTypeLabel(int type)
|
||||
{
|
||||
if (type == ESM::AI_Wander) return "Wander";
|
||||
else if (type == ESM::AI_Travel) return "Travel";
|
||||
else if (type == ESM::AI_Follow) return "Follow";
|
||||
else if (type == ESM::AI_Escort) return "Escort";
|
||||
else if (type == ESM::AI_Activate) return "Activate";
|
||||
else return "Invalid";
|
||||
}
|
||||
|
||||
std::string magicEffectLabel(int idx)
|
||||
{
|
||||
const char* magicEffectLabels [] = {
|
||||
"Water Breathing",
|
||||
"Swift Swim",
|
||||
"Water Walking",
|
||||
"Shield",
|
||||
"Fire Shield",
|
||||
"Lightning Shield",
|
||||
"Frost Shield",
|
||||
"Burden",
|
||||
"Feather",
|
||||
"Jump",
|
||||
"Levitate",
|
||||
"SlowFall",
|
||||
"Lock",
|
||||
"Open",
|
||||
"Fire Damage",
|
||||
"Shock Damage",
|
||||
"Frost Damage",
|
||||
"Drain Attribute",
|
||||
"Drain Health",
|
||||
"Drain Magicka",
|
||||
"Drain Fatigue",
|
||||
"Drain Skill",
|
||||
"Damage Attribute",
|
||||
"Damage Health",
|
||||
"Damage Magicka",
|
||||
"Damage Fatigue",
|
||||
"Damage Skill",
|
||||
"Poison",
|
||||
"Weakness to Fire",
|
||||
"Weakness to Frost",
|
||||
"Weakness to Shock",
|
||||
"Weakness to Magicka",
|
||||
"Weakness to Common Disease",
|
||||
"Weakness to Blight Disease",
|
||||
"Weakness to Corprus Disease",
|
||||
"Weakness to Poison",
|
||||
"Weakness to Normal Weapons",
|
||||
"Disintegrate Weapon",
|
||||
"Disintegrate Armor",
|
||||
"Invisibility",
|
||||
"Chameleon",
|
||||
"Light",
|
||||
"Sanctuary",
|
||||
"Night Eye",
|
||||
"Charm",
|
||||
"Paralyze",
|
||||
"Silence",
|
||||
"Blind",
|
||||
"Sound",
|
||||
"Calm Humanoid",
|
||||
"Calm Creature",
|
||||
"Frenzy Humanoid",
|
||||
"Frenzy Creature",
|
||||
"Demoralize Humanoid",
|
||||
"Demoralize Creature",
|
||||
"Rally Humanoid",
|
||||
"Rally Creature",
|
||||
"Dispel",
|
||||
"Soultrap",
|
||||
"Telekinesis",
|
||||
"Mark",
|
||||
"Recall",
|
||||
"Divine Intervention",
|
||||
"Almsivi Intervention",
|
||||
"Detect Animal",
|
||||
"Detect Enchantment",
|
||||
"Detect Key",
|
||||
"Spell Absorption",
|
||||
"Reflect",
|
||||
"Cure Common Disease",
|
||||
"Cure Blight Disease",
|
||||
"Cure Corprus Disease",
|
||||
"Cure Poison",
|
||||
"Cure Paralyzation",
|
||||
"Restore Attribute",
|
||||
"Restore Health",
|
||||
"Restore Magicka",
|
||||
"Restore Fatigue",
|
||||
"Restore Skill",
|
||||
"Fortify Attribute",
|
||||
"Fortify Health",
|
||||
"Fortify Magicka",
|
||||
"Fortify Fatigue",
|
||||
"Fortify Skill",
|
||||
"Fortify Maximum Magicka",
|
||||
"Absorb Attribute",
|
||||
"Absorb Health",
|
||||
"Absorb Magicka",
|
||||
"Absorb Fatigue",
|
||||
"Absorb Skill",
|
||||
"Resist Fire",
|
||||
"Resist Frost",
|
||||
"Resist Shock",
|
||||
"Resist Magicka",
|
||||
"Resist Common Disease",
|
||||
"Resist Blight Disease",
|
||||
"Resist Corprus Disease",
|
||||
"Resist Poison",
|
||||
"Resist Normal Weapons",
|
||||
"Resist Paralysis",
|
||||
"Remove Curse",
|
||||
"Turn Undead",
|
||||
"Summon Scamp",
|
||||
"Summon Clannfear",
|
||||
"Summon Daedroth",
|
||||
"Summon Dremora",
|
||||
"Summon Ancestral Ghost",
|
||||
"Summon Skeletal Minion",
|
||||
"Summon Bonewalker",
|
||||
"Summon Greater Bonewalker",
|
||||
"Summon Bonelord",
|
||||
"Summon Winged Twilight",
|
||||
"Summon Hunger",
|
||||
"Summon Golden Saint",
|
||||
"Summon Flame Atronach",
|
||||
"Summon Frost Atronach",
|
||||
"Summon Storm Atronach",
|
||||
"Fortify Attack",
|
||||
"Command Creature",
|
||||
"Command Humanoid",
|
||||
"Bound Dagger",
|
||||
"Bound Longsword",
|
||||
"Bound Mace",
|
||||
"Bound Battle Axe",
|
||||
"Bound Spear",
|
||||
"Bound Longbow",
|
||||
"EXTRA SPELL",
|
||||
"Bound Cuirass",
|
||||
"Bound Helm",
|
||||
"Bound Boots",
|
||||
"Bound Shield",
|
||||
"Bound Gloves",
|
||||
"Corprus",
|
||||
"Vampirism",
|
||||
"Summon Centurion Sphere",
|
||||
"Sun Damage",
|
||||
"Stunted Magicka",
|
||||
"Summon Fabricant",
|
||||
"sEffectSummonCreature01",
|
||||
"sEffectSummonCreature02",
|
||||
"sEffectSummonCreature03",
|
||||
"sEffectSummonCreature04",
|
||||
"sEffectSummonCreature05"
|
||||
};
|
||||
if (idx >= 0 && idx <= 143)
|
||||
return magicEffectLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string attributeLabel(int idx)
|
||||
{
|
||||
const char* attributeLabels [] = {
|
||||
"Strength",
|
||||
"Intelligence",
|
||||
"Willpower",
|
||||
"Agility",
|
||||
"Speed",
|
||||
"Endurance",
|
||||
"Personality",
|
||||
"Luck"
|
||||
};
|
||||
if (idx >= 0 && idx <= 7)
|
||||
return attributeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string spellTypeLabel(int idx)
|
||||
{
|
||||
const char* spellTypeLabels [] = {
|
||||
"Spells",
|
||||
"Abilities",
|
||||
"Blight Disease",
|
||||
"Disease",
|
||||
"Curse",
|
||||
"Powers"
|
||||
};
|
||||
if (idx >= 0 && idx <= 5)
|
||||
return spellTypeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string specializationLabel(int idx)
|
||||
{
|
||||
const char* specializationLabels [] = {
|
||||
"Combat",
|
||||
"Magic",
|
||||
"Stealth"
|
||||
};
|
||||
if (idx >= 0 && idx <= 2)
|
||||
return specializationLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string skillLabel(int idx)
|
||||
{
|
||||
const char* skillLabels [] = {
|
||||
"Block",
|
||||
"Armorer",
|
||||
"Medium Armor",
|
||||
"Heavy Armor",
|
||||
"Blunt Weapon",
|
||||
"Long Blade",
|
||||
"Axe",
|
||||
"Spear",
|
||||
"Athletics",
|
||||
"Enchant",
|
||||
"Destruction",
|
||||
"Alteration",
|
||||
"Illusion",
|
||||
"Conjuration",
|
||||
"Mysticism",
|
||||
"Restoration",
|
||||
"Alchemy",
|
||||
"Unarmored",
|
||||
"Security",
|
||||
"Sneak",
|
||||
"Acrobatics",
|
||||
"Light Armor",
|
||||
"Short Blade",
|
||||
"Marksman",
|
||||
"Mercantile",
|
||||
"Speechcraft",
|
||||
"Hand-to-hand"
|
||||
};
|
||||
if (idx >= 0 && idx <= 27)
|
||||
return skillLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string apparatusTypeLabel(int idx)
|
||||
{
|
||||
const char* apparatusTypeLabels [] = {
|
||||
"Mortar",
|
||||
"Alembic",
|
||||
"Calcinator",
|
||||
"Retort",
|
||||
};
|
||||
if (idx >= 0 && idx <= 3)
|
||||
return apparatusTypeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string rangeTypeLabel(int idx)
|
||||
{
|
||||
const char* rangeTypeLabels [] = {
|
||||
"Self",
|
||||
"Touch",
|
||||
"Target"
|
||||
};
|
||||
if (idx >= 0 && idx <= 3)
|
||||
return rangeTypeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string schoolLabel(int idx)
|
||||
{
|
||||
const char* schoolLabels [] = {
|
||||
"Alteration",
|
||||
"Conjuration",
|
||||
"Destruction",
|
||||
"Illusion",
|
||||
"Mysticism",
|
||||
"Restoration"
|
||||
};
|
||||
if (idx >= 0 && idx <= 5)
|
||||
return schoolLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string enchantTypeLabel(int idx)
|
||||
{
|
||||
const char* enchantTypeLabels [] = {
|
||||
"Cast Once",
|
||||
"Cast When Strikes",
|
||||
"Cast When Used",
|
||||
"Constant Effect"
|
||||
};
|
||||
if (idx >= 0 && idx <= 3)
|
||||
return enchantTypeLabels[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
std::string ruleFunction(int idx)
|
||||
{
|
||||
std::string ruleFunctions[] = {
|
||||
"Reaction Low",
|
||||
"Reaction High",
|
||||
"Rank Requirement",
|
||||
"NPC? Reputation",
|
||||
"Health Percent",
|
||||
"Player Reputation",
|
||||
"NPC Level",
|
||||
"Player Health Percent",
|
||||
"Player Magicka",
|
||||
"Player Fatigue",
|
||||
"Player Attribute Strength",
|
||||
"Player Skill Block",
|
||||
"Player Skill Armorer",
|
||||
"Player Skill Medium Armor",
|
||||
"Player Skill Heavy Armor",
|
||||
"Player Skill Blunt Weapon",
|
||||
"Player Skill Long Blade",
|
||||
"Player Skill Axe",
|
||||
"Player Skill Spear",
|
||||
"Player Skill Athletics",
|
||||
"Player Skill Enchant",
|
||||
"Player Skill Destruction",
|
||||
"Player Skill Alteration",
|
||||
"Player Skill Illusion",
|
||||
"Player Skill Conjuration",
|
||||
"Player Skill Mysticism",
|
||||
"Player SKill Restoration",
|
||||
"Player Skill Alchemy",
|
||||
"Player Skill Unarmored",
|
||||
"Player Skill Security",
|
||||
"Player Skill Sneak",
|
||||
"Player Skill Acrobatics",
|
||||
"Player Skill Light Armor",
|
||||
"Player Skill Short Blade",
|
||||
"Player Skill Marksman",
|
||||
"Player Skill Mercantile",
|
||||
"Player Skill Speechcraft",
|
||||
"Player Skill Hand to Hand",
|
||||
"Player Gender",
|
||||
"Player Expelled from Faction",
|
||||
"Player Diseased (Common)",
|
||||
"Player Diseased (Blight)",
|
||||
"Player Clothing Modifier",
|
||||
"Player Crime Level",
|
||||
"Player Same Sex",
|
||||
"Player Same Race",
|
||||
"Player Same Faction",
|
||||
"Faction Rank Difference",
|
||||
"Player Detected",
|
||||
"Alarmed",
|
||||
"Choice Selected",
|
||||
"Player Attribute Intelligence",
|
||||
"Player Attribute Willpower",
|
||||
"Player Attribute Agility",
|
||||
"Player Attribute Speed",
|
||||
"Player Attribute Endurance",
|
||||
"Player Attribute Personality",
|
||||
"Player Attribute Luck",
|
||||
"Player Diseased (Corprus)",
|
||||
"Weather",
|
||||
"Player is a Vampire",
|
||||
"Player Level",
|
||||
"Attacked",
|
||||
"NPC Talked to Player",
|
||||
"Player Health",
|
||||
"Creature Target",
|
||||
"Friend Hit",
|
||||
"Fight",
|
||||
"Hello",
|
||||
"Alarm",
|
||||
"Flee",
|
||||
"Should Attack",
|
||||
//Unkown but causes NPCs to growl and roar.
|
||||
"UNKNOWN 72"
|
||||
};
|
||||
if (idx >= 0 && idx <= 72)
|
||||
return ruleFunctions[idx];
|
||||
else
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
// The "unused flag bits" should probably be defined alongside the
|
||||
// defined bits in the ESM component. The names of the flag bits are
|
||||
// very inconsistent.
|
||||
|
||||
std::string bodyPartFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::BodyPart::BPF_Female) properties += "Female ";
|
||||
if (flags & ESM::BodyPart::BPF_Playable) properties += "Playable ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::BodyPart::BPF_Female|
|
||||
ESM::BodyPart::BPF_Playable));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string cellFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Cell::HasWater) properties += "HasWater ";
|
||||
if (flags & ESM::Cell::Interior) properties += "Interior ";
|
||||
if (flags & ESM::Cell::NoSleep) properties += "NoSleep ";
|
||||
if (flags & ESM::Cell::QuasiEx) properties += "QuasiEx ";
|
||||
// This used value is not in the ESM component.
|
||||
if (flags & 0x00000040) properties += "Unknown ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Cell::HasWater|
|
||||
ESM::Cell::Interior|
|
||||
ESM::Cell::NoSleep|
|
||||
ESM::Cell::QuasiEx|
|
||||
0x00000040));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string containerFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Container::Unknown) properties += "Unknown ";
|
||||
if (flags & ESM::Container::Organic) properties += "Organic ";
|
||||
if (flags & ESM::Container::Respawn) properties += "Respawn ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Container::Unknown|
|
||||
ESM::Container::Organic|
|
||||
ESM::Container::Respawn));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string creatureFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Creature::None) properties += "All ";
|
||||
if (flags & ESM::Creature::Walks) properties += "Walks ";
|
||||
if (flags & ESM::Creature::Swims) properties += "Swims ";
|
||||
if (flags & ESM::Creature::Flies) properties += "Flies ";
|
||||
if (flags & ESM::Creature::Biped) properties += "Biped ";
|
||||
if (flags & ESM::Creature::Respawn) properties += "Respawn ";
|
||||
if (flags & ESM::Creature::Weapon) properties += "Weapon ";
|
||||
if (flags & ESM::Creature::Skeleton) properties += "Skeleton ";
|
||||
if (flags & ESM::Creature::Metal) properties += "Metal ";
|
||||
if (flags & ESM::Creature::Essential) properties += "Essential ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Creature::None|
|
||||
ESM::Creature::Walks|
|
||||
ESM::Creature::Swims|
|
||||
ESM::Creature::Flies|
|
||||
ESM::Creature::Biped|
|
||||
ESM::Creature::Respawn|
|
||||
ESM::Creature::Weapon|
|
||||
ESM::Creature::Skeleton|
|
||||
ESM::Creature::Metal|
|
||||
ESM::Creature::Essential));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string landFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
// The ESM component says that this first four bits are used, but
|
||||
// only the first three bits are used as far as I can tell.
|
||||
// There's also no enumeration of the bit in the ESM component.
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & 0x00000001) properties += "Unknown1 ";
|
||||
if (flags & 0x00000004) properties += "Unknown3 ";
|
||||
if (flags & 0x00000002) properties += "Unknown2 ";
|
||||
if (flags & 0xFFFFFFF8) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string leveledListFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::LeveledListBase::AllLevels) properties += "AllLevels ";
|
||||
// This flag apparently not present on creature lists...
|
||||
if (flags & ESM::LeveledListBase::Each) properties += "Each ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::LeveledListBase::AllLevels|
|
||||
ESM::LeveledListBase::Each));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string lightFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Light::Dynamic) properties += "Dynamic ";
|
||||
if (flags & ESM::Light::Fire) properties += "Fire ";
|
||||
if (flags & ESM::Light::Carry) properties += "Carry ";
|
||||
if (flags & ESM::Light::Flicker) properties += "Flicker ";
|
||||
if (flags & ESM::Light::FlickerSlow) properties += "FlickerSlow ";
|
||||
if (flags & ESM::Light::Pulse) properties += "Pulse ";
|
||||
if (flags & ESM::Light::PulseSlow) properties += "PulseSlow ";
|
||||
if (flags & ESM::Light::Negative) properties += "Negative ";
|
||||
if (flags & ESM::Light::OffDefault) properties += "OffDefault ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Light::Dynamic|
|
||||
ESM::Light::Fire|
|
||||
ESM::Light::Carry|
|
||||
ESM::Light::Flicker|
|
||||
ESM::Light::FlickerSlow|
|
||||
ESM::Light::Pulse|
|
||||
ESM::Light::PulseSlow|
|
||||
ESM::Light::Negative|
|
||||
ESM::Light::OffDefault));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string magicEffectFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
// Enchanting & SpellMaking occur on the same list of effects.
|
||||
// "EXTRA SPELL" appears in the construction set under both the
|
||||
// spell making and enchanting tabs as an allowed effect. Since
|
||||
// most of the effects without this flags are defective in various
|
||||
// ways, it's still very unclear what these flag bits are.
|
||||
if (flags & ESM::MagicEffect::SpellMaking) properties += "SpellMaking ";
|
||||
if (flags & ESM::MagicEffect::Enchanting) properties += "Enchanting ";
|
||||
if (flags & 0x00000040) properties += "RangeNoSelf ";
|
||||
if (flags & 0x00000080) properties += "RangeTouch ";
|
||||
if (flags & 0x00000100) properties += "RangeTarget ";
|
||||
if (flags & 0x00001000) properties += "Unknown2 ";
|
||||
if (flags & 0x00000001) properties += "AffectSkill ";
|
||||
if (flags & 0x00000002) properties += "AffectAttribute ";
|
||||
if (flags & ESM::MagicEffect::NoDuration) properties += "NoDuration ";
|
||||
if (flags & 0x00000008) properties += "NoMagnitude ";
|
||||
if (flags & 0x00000010) properties += "Negative ";
|
||||
if (flags & 0x00000020) properties += "Unknown1 ";
|
||||
// ESM componet says 0x800 is negative, but none of the magic
|
||||
// effects have this flags set.
|
||||
if (flags & ESM::MagicEffect::Negative) properties += "Unused ";
|
||||
// Since only Chameleon has this flag it could be anything
|
||||
// that uniquely distinguishes Chameleon.
|
||||
if (flags & 0x00002000) properties += "Chameleon ";
|
||||
if (flags & 0x00004000) properties += "Bound ";
|
||||
if (flags & 0x00008000) properties += "Summon ";
|
||||
// Calm, Demoralize, Frenzy, Lock, Open, Rally, Soultrap, Turn Unded
|
||||
if (flags & 0x00010000) properties += "Unknown3 ";
|
||||
if (flags & 0x00020000) properties += "Absorb ";
|
||||
if (flags & 0xFFFC0000) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string npcFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
// Mythicmods and the ESM component differ. Mythicmods says
|
||||
// 0x8=None and 0x10=AutoCalc, while our code defines 0x8 as
|
||||
// AutoCalc. The former seems to be correct. All Bethesda
|
||||
// records have bit 0x8 set. A suspiciously large portion of
|
||||
// females have autocalc turned off.
|
||||
if (flags & ESM::NPC::Autocalc) properties += "Unknown ";
|
||||
if (flags & 0x00000010) properties += "Autocalc ";
|
||||
if (flags & ESM::NPC::Female) properties += "Female ";
|
||||
if (flags & ESM::NPC::Respawn) properties += "Respawn ";
|
||||
if (flags & ESM::NPC::Essential) properties += "Essential ";
|
||||
// These two flags do not appear on any NPCs and may have been
|
||||
// confused with the flags for creatures.
|
||||
if (flags & ESM::NPC::Skeleton) properties += "Skeleton ";
|
||||
if (flags & ESM::NPC::Metal) properties += "Metal ";
|
||||
// Whether corpses persist is a bit that is unaccounted for,
|
||||
// however the only unknown bit occurs on ALL records, and
|
||||
// relatively few NPCs have this bit set.
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::NPC::Autocalc|
|
||||
0x00000010|
|
||||
ESM::NPC::Female|
|
||||
ESM::NPC::Respawn|
|
||||
ESM::NPC::Essential|
|
||||
ESM::NPC::Skeleton|
|
||||
ESM::NPC::Metal));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string raceFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
// All races have the playable flag set in Bethesda files.
|
||||
if (flags & ESM::Race::Playable) properties += "Playable ";
|
||||
if (flags & ESM::Race::Beast) properties += "Beast ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Race::Playable|
|
||||
ESM::Race::Beast));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string spellFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
if (flags & ESM::Spell::F_Autocalc) properties += "Autocalc ";
|
||||
if (flags & ESM::Spell::F_PCStart) properties += "PCStart ";
|
||||
if (flags & ESM::Spell::F_Always) properties += "Always ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Spell::F_Autocalc|
|
||||
ESM::Spell::F_PCStart|
|
||||
ESM::Spell::F_Always));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string weaponFlags(int flags)
|
||||
{
|
||||
std::string properties = "";
|
||||
if (flags == 0) properties += "[None] ";
|
||||
// The interpretation of the flags are still unclear to me.
|
||||
// Apparently you can't be Silver without being Magical? Many of
|
||||
// the "Magical" weapons don't have enchantments of any sort.
|
||||
if (flags & ESM::Weapon::Magical) properties += "Magical ";
|
||||
if (flags & ESM::Weapon::Silver) properties += "Silver ";
|
||||
int unused = (0xFFFFFFFF ^
|
||||
(ESM::Weapon::Magical|
|
||||
ESM::Weapon::Silver));
|
||||
if (flags & unused) properties += "Invalid ";
|
||||
properties += str(boost::format("(0x%08X)") % flags);
|
||||
return properties;
|
||||
}
|
64
apps/esmtool/labels.hpp
Normal file
64
apps/esmtool/labels.hpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifndef OPENMW_ESMTOOL_LABELS_H
|
||||
#define OPENMW_ESMTOOL_LABELS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string bodyPartLabel(char idx);
|
||||
std::string meshPartLabel(char idx);
|
||||
std::string meshTypeLabel(char idx);
|
||||
std::string clothingTypeLabel(int idx);
|
||||
std::string armorTypeLabel(int idx);
|
||||
std::string dialogTypeLabel(int idx);
|
||||
std::string questStatusLabel(int idx);
|
||||
std::string creatureTypeLabel(int idx);
|
||||
std::string soundTypeLabel(int idx);
|
||||
std::string weaponTypeLabel(int idx);
|
||||
|
||||
// This function's a bit different because the types are record types,
|
||||
// not consecutive values.
|
||||
std::string aiTypeLabel(int type);
|
||||
|
||||
// This one's also a bit different, because it enumerates dialog
|
||||
// select rule functions, not types. Structurally, it still converts
|
||||
// indexes to strings for display.
|
||||
std::string ruleFunction(int idx);
|
||||
|
||||
// The labels below here can all be loaded from GMSTs, but are not
|
||||
// currently because among other things, that requires loading the
|
||||
// GMSTs before dumping any of the records.
|
||||
|
||||
// If the data format supported ordered lists of GMSTs (post 1.0), the
|
||||
// lists could define the valid values, their localization strings,
|
||||
// and the indexes for referencing the types in other records in the
|
||||
// database. Then a single label function could work for all types.
|
||||
|
||||
std::string magicEffectLabel(int idx);
|
||||
std::string attributeLabel(int idx);
|
||||
std::string spellTypeLabel(int idx);
|
||||
std::string specializationLabel(int idx);
|
||||
std::string skillLabel(int idx);
|
||||
std::string apparatusTypeLabel(int idx);
|
||||
std::string rangeTypeLabel(int idx);
|
||||
std::string schoolLabel(int idx);
|
||||
std::string enchantTypeLabel(int idx);
|
||||
|
||||
// The are the flag functions that convert a bitmask into a list of
|
||||
// human readble strings representing the set bits.
|
||||
|
||||
std::string bodyPartFlags(int flags);
|
||||
std::string cellFlags(int flags);
|
||||
std::string containerFlags(int flags);
|
||||
std::string creatureFlags(int flags);
|
||||
std::string landFlags(int flags);
|
||||
std::string leveledListFlags(int flags);
|
||||
std::string lightFlags(int flags);
|
||||
std::string magicEffectFlags(int flags);
|
||||
std::string npcFlags(int flags);
|
||||
std::string raceFlags(int flags);
|
||||
std::string spellFlags(int flags);
|
||||
std::string weaponFlags(int flags);
|
||||
|
||||
// Missing flags functions:
|
||||
// aiServicesFlags, possibly more
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,7 @@ namespace EsmTool
|
|||
protected:
|
||||
std::string mId;
|
||||
int mFlags;
|
||||
int mType;
|
||||
ESM::NAME mType;
|
||||
|
||||
public:
|
||||
RecordBase () {}
|
||||
|
@ -42,7 +42,7 @@ namespace EsmTool
|
|||
mFlags = flags;
|
||||
}
|
||||
|
||||
int getType() const {
|
||||
ESM::NAME getType() const {
|
||||
return mType;
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ namespace EsmTool
|
|||
virtual void save(ESM::ESMWriter &esm) = 0;
|
||||
virtual void print() = 0;
|
||||
|
||||
static RecordBase *create(int type);
|
||||
static RecordBase *create(ESM::NAME type);
|
||||
|
||||
// just make it a bit shorter
|
||||
template <class T>
|
||||
|
|
|
@ -1,42 +1,56 @@
|
|||
set(LAUNCHER
|
||||
datafilespage.cpp
|
||||
graphicspage.cpp
|
||||
lineedit.cpp
|
||||
main.cpp
|
||||
maindialog.cpp
|
||||
naturalsort.cpp
|
||||
playpage.cpp
|
||||
pluginsmodel.cpp
|
||||
pluginsview.cpp
|
||||
filedialog.cpp
|
||||
|
||||
model/datafilesmodel.cpp
|
||||
model/modelitem.cpp
|
||||
model/esm/esmfile.cpp
|
||||
|
||||
utils/filedialog.cpp
|
||||
utils/naturalsort.cpp
|
||||
utils/lineedit.cpp
|
||||
utils/profilescombobox.cpp
|
||||
utils/textinputdialog.cpp
|
||||
|
||||
launcher.rc
|
||||
)
|
||||
|
||||
set(LAUNCHER_HEADER
|
||||
combobox.hpp
|
||||
datafilespage.hpp
|
||||
graphicspage.hpp
|
||||
lineedit.hpp
|
||||
maindialog.hpp
|
||||
naturalsort.hpp
|
||||
playpage.hpp
|
||||
pluginsmodel.hpp
|
||||
pluginsview.hpp
|
||||
filedialog.hpp
|
||||
|
||||
model/datafilesmodel.hpp
|
||||
model/modelitem.hpp
|
||||
model/esm/esmfile.hpp
|
||||
|
||||
utils/lineedit.hpp
|
||||
utils/filedialog.hpp
|
||||
utils/naturalsort.hpp
|
||||
utils/profilescombobox.hpp
|
||||
utils/textinputdialog.hpp
|
||||
|
||||
)
|
||||
|
||||
# Headers that must be pre-processed
|
||||
set(LAUNCHER_HEADER_MOC
|
||||
combobox.hpp
|
||||
datafilespage.hpp
|
||||
graphicspage.hpp
|
||||
lineedit.hpp
|
||||
maindialog.hpp
|
||||
playpage.hpp
|
||||
pluginsmodel.hpp
|
||||
pluginsview.hpp
|
||||
filedialog.hpp
|
||||
|
||||
model/datafilesmodel.hpp
|
||||
model/modelitem.hpp
|
||||
model/esm/esmfile.hpp
|
||||
|
||||
utils/lineedit.hpp
|
||||
utils/filedialog.hpp
|
||||
utils/profilescombobox.hpp
|
||||
utils/textinputdialog.hpp
|
||||
)
|
||||
|
||||
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC})
|
||||
|
@ -75,7 +89,7 @@ add_executable(omwlauncher
|
|||
target_link_libraries(omwlauncher
|
||||
${Boost_LIBRARIES}
|
||||
${OGRE_LIBRARIES}
|
||||
${OGRE_STATIC_PLUGINS}
|
||||
${OGRE_STATIC_PLUGINS}
|
||||
${QT_LIBRARIES}
|
||||
components
|
||||
)
|
||||
|
@ -87,8 +101,6 @@ endif()
|
|||
if (APPLE)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
"${APP_BUNDLE_DIR}/../launcher.qss")
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
||||
"${APP_BUNDLE_DIR}/../launcher.cfg")
|
||||
else()
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources/launcher.qss")
|
||||
|
@ -96,9 +108,6 @@ else()
|
|||
# Fallback in case getGlobalDataPath does not point to resources
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss")
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.cfg")
|
||||
endif()
|
||||
|
||||
if (BUILD_WITH_CODE_COVERAGE)
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef COMBOBOX_H
|
||||
#define COMBOBOX_H
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
class ComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QString oldText;
|
||||
public:
|
||||
ComboBox(QWidget *parent=0) : QComboBox(parent), oldText()
|
||||
{
|
||||
connect(this,SIGNAL(editTextChanged(const QString&)), this,
|
||||
SLOT(textChangedSlot(const QString&)));
|
||||
connect(this,SIGNAL(currentIndexChanged(const QString&)), this,
|
||||
SLOT(textChangedSlot(const QString&)));
|
||||
}
|
||||
private slots:
|
||||
void textChangedSlot(const QString &newText)
|
||||
{
|
||||
emit textChanged(oldText, newText);
|
||||
oldText = newText;
|
||||
}
|
||||
signals:
|
||||
void textChanged(const QString &oldText, const QString &newText);
|
||||
};
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -3,24 +3,20 @@
|
|||
|
||||
#include <QWidget>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include "utils/profilescombobox.hpp"
|
||||
#include <components/files/collections.hpp>
|
||||
|
||||
#include "combobox.hpp"
|
||||
|
||||
class QTableWidget;
|
||||
class QStandardItemModel;
|
||||
class QItemSelection;
|
||||
class QItemSelectionModel;
|
||||
class QTableView;
|
||||
class QSortFilterProxyModel;
|
||||
class QStringListModel;
|
||||
class QSettings;
|
||||
class QAction;
|
||||
class QToolBar;
|
||||
class QMenu;
|
||||
class PluginsModel;
|
||||
class PluginsView;
|
||||
class ComboBox;
|
||||
class ProfilesComboBox;
|
||||
class DataFilesModel;
|
||||
|
||||
class TextInputDialog;
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
|
||||
|
@ -31,52 +27,51 @@ class DataFilesPage : public QWidget
|
|||
public:
|
||||
DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0);
|
||||
|
||||
ComboBox *mProfilesComboBox;
|
||||
ProfilesComboBox *mProfilesComboBox;
|
||||
|
||||
void writeConfig(QString profile = QString());
|
||||
bool showDataFilesWarning();
|
||||
bool setupDataFiles();
|
||||
|
||||
public slots:
|
||||
void masterSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void setCheckState(QModelIndex index);
|
||||
|
||||
void filterChanged(const QString filter);
|
||||
void showContextMenu(const QPoint &point);
|
||||
void profileChanged(const QString &previous, const QString ¤t);
|
||||
void profileRenamed(const QString &previous, const QString ¤t);
|
||||
void updateOkButton(const QString &text);
|
||||
|
||||
// Action slots
|
||||
void newProfile();
|
||||
void copyProfile();
|
||||
void deleteProfile();
|
||||
void moveUp();
|
||||
void moveDown();
|
||||
void moveTop();
|
||||
void moveBottom();
|
||||
// void moveUp();
|
||||
// void moveDown();
|
||||
// void moveTop();
|
||||
// void moveBottom();
|
||||
void check();
|
||||
void uncheck();
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
QTableWidget *mMastersWidget;
|
||||
PluginsView *mPluginsTable;
|
||||
|
||||
QStandardItemModel *mDataFilesModel;
|
||||
PluginsModel *mPluginsModel;
|
||||
DataFilesModel *mMastersModel;
|
||||
DataFilesModel *mPluginsModel;
|
||||
|
||||
QSortFilterProxyModel *mPluginsProxyModel;
|
||||
QItemSelectionModel *mPluginsSelectModel;
|
||||
|
||||
QTableView *mMastersTable;
|
||||
QTableView *mPluginsTable;
|
||||
|
||||
QToolBar *mProfileToolBar;
|
||||
QMenu *mContextMenu;
|
||||
|
||||
QAction *mNewProfileAction;
|
||||
QAction *mCopyProfileAction;
|
||||
QAction *mDeleteProfileAction;
|
||||
|
||||
QAction *mMoveUpAction;
|
||||
QAction *mMoveDownAction;
|
||||
QAction *mMoveTopAction;
|
||||
QAction *mMoveBottomAction;
|
||||
// QAction *mMoveUpAction;
|
||||
// QAction *mMoveDownAction;
|
||||
// QAction *mMoveTopAction;
|
||||
// QAction *mMoveBottomAction;
|
||||
QAction *mCheckAction;
|
||||
QAction *mUncheckAction;
|
||||
|
||||
|
@ -86,17 +81,14 @@ private:
|
|||
|
||||
QSettings *mLauncherConfig;
|
||||
|
||||
const QStringList checkedPlugins();
|
||||
const QStringList selectedMasters();
|
||||
TextInputDialog *mNewProfileDialog;
|
||||
|
||||
// const QStringList checkedPlugins();
|
||||
// const QStringList selectedMasters();
|
||||
|
||||
void addDataFiles(Files::Collections &fileCollections, const QString &encoding);
|
||||
void addPlugins(const QModelIndex &index);
|
||||
void removePlugins(const QModelIndex &index);
|
||||
void uncheckPlugins();
|
||||
void createActions();
|
||||
void setupConfig();
|
||||
void readConfig();
|
||||
void scrollToSelection();
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
#include <components/files/ogreplugin.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include "utils/naturalsort.hpp"
|
||||
|
||||
#include "graphicspage.hpp"
|
||||
#include "naturalsort.hpp"
|
||||
|
||||
QString getAspect(int x, int y)
|
||||
{
|
||||
|
@ -280,20 +281,18 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer)
|
|||
assert (tokens.size() >= 3);
|
||||
QString resolutionStr = tokens.at(0) + QString(" x ") + tokens.at(2);
|
||||
|
||||
// do not add duplicate resolutions
|
||||
if (!result.contains(resolutionStr)) {
|
||||
QString aspect = getAspect(tokens.at(0).toInt(),tokens.at(2).toInt());
|
||||
|
||||
QString aspect = getAspect(tokens.at(0).toInt(),tokens.at(2).toInt());
|
||||
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) {
|
||||
resolutionStr.append(tr("\t(Widescreen ") + aspect + ")");
|
||||
|
||||
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) {
|
||||
resolutionStr.append(tr("\t(Widescreen ") + aspect + ")");
|
||||
|
||||
} else if (aspect == QLatin1String("4:3")) {
|
||||
resolutionStr.append(tr("\t(Standard 4:3)"));
|
||||
}
|
||||
|
||||
result << resolutionStr;
|
||||
} else if (aspect == QLatin1String("4:3")) {
|
||||
resolutionStr.append(tr("\t(Standard 4:3)"));
|
||||
}
|
||||
|
||||
// do not add duplicate resolutions
|
||||
if (!result.contains(resolutionStr))
|
||||
result << resolutionStr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ int main(int argc, char *argv[])
|
|||
// Now we make sure the current dir is set to application path
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
#ifdef Q_OS_MAC
|
||||
if (dir.dirName() == "MacOS") {
|
||||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
|
|
|
@ -141,11 +141,11 @@ void MainDialog::createPages()
|
|||
|
||||
connect(mPlayPage->mProfilesComboBox,
|
||||
SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(profileChanged(int)));
|
||||
mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int)));
|
||||
|
||||
connect(mDataFilesPage->mProfilesComboBox,
|
||||
SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(profileChanged(int)));
|
||||
mPlayPage->mProfilesComboBox, SLOT(setCurrentIndex(int)));
|
||||
|
||||
}
|
||||
|
||||
|
@ -196,23 +196,6 @@ bool MainDialog::setup()
|
|||
return true;
|
||||
}
|
||||
|
||||
void MainDialog::profileChanged(int index)
|
||||
{
|
||||
// Just to be sure, should always have a selection
|
||||
if (!mIconWidget->selectionModel()->hasSelection()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString currentPage = mIconWidget->currentItem()->data(Qt::DisplayRole).toString();
|
||||
if (currentPage == QLatin1String("Play")) {
|
||||
mDataFilesPage->mProfilesComboBox->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
if (currentPage == QLatin1String("Data Files")) {
|
||||
mPlayPage->mProfilesComboBox->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
|
||||
{
|
||||
if (!current)
|
||||
|
@ -244,10 +227,10 @@ void MainDialog::play()
|
|||
const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string();
|
||||
mSettings.saveUser(settingspath);
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#ifdef Q_OS_WIN
|
||||
QString game = "./openmw.exe";
|
||||
QFile file(game);
|
||||
#elif defined(Q_WS_MAC)
|
||||
#elif defined(Q_OS_MAC)
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
QString game = dir.absoluteFilePath("openmw");
|
||||
QFile file(game);
|
||||
|
|
|
@ -27,7 +27,6 @@ public:
|
|||
public slots:
|
||||
void changePage(QListWidgetItem *current, QListWidgetItem *previous);
|
||||
void play();
|
||||
void profileChanged(int index);
|
||||
bool setup();
|
||||
|
||||
private:
|
||||
|
|
474
apps/launcher/model/datafilesmodel.cpp
Normal file
474
apps/launcher/model/datafilesmodel.cpp
Normal file
|
@ -0,0 +1,474 @@
|
|||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
#include "esm/esmfile.hpp"
|
||||
|
||||
#include "../utils/naturalsort.hpp"
|
||||
|
||||
#include "datafilesmodel.hpp"
|
||||
|
||||
DataFilesModel::DataFilesModel(QObject *parent) :
|
||||
QAbstractTableModel(parent)
|
||||
{
|
||||
mEncoding = QString("win1252");
|
||||
}
|
||||
|
||||
DataFilesModel::~DataFilesModel()
|
||||
{
|
||||
}
|
||||
|
||||
void DataFilesModel::setEncoding(const QString &encoding)
|
||||
{
|
||||
mEncoding = encoding;
|
||||
}
|
||||
|
||||
void DataFilesModel::setCheckState(const QModelIndex &index, Qt::CheckState state)
|
||||
{
|
||||
setData(index, state, Qt::CheckStateRole);
|
||||
}
|
||||
|
||||
Qt::CheckState DataFilesModel::checkState(const QModelIndex &index)
|
||||
{
|
||||
EsmFile *file = item(index.row());
|
||||
return mCheckStates[file->fileName()];
|
||||
}
|
||||
|
||||
int DataFilesModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : 9;
|
||||
}
|
||||
|
||||
int DataFilesModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : mFiles.count();
|
||||
}
|
||||
|
||||
|
||||
bool DataFilesModel::moveRow(int oldrow, int row, const QModelIndex &parent)
|
||||
{
|
||||
if (oldrow < 0 || row < 0 || oldrow == row)
|
||||
return false;
|
||||
|
||||
emit layoutAboutToBeChanged();
|
||||
//emit beginMoveRows(parent, oldrow, oldrow, parent, row);
|
||||
mFiles.swap(oldrow, row);
|
||||
//emit endInsertRows();
|
||||
emit layoutChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariant DataFilesModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
EsmFile *file = item(index.row());
|
||||
|
||||
if (!file)
|
||||
return QVariant();
|
||||
|
||||
const int column = index.column();
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
|
||||
switch (column) {
|
||||
case 0:
|
||||
return file->fileName();
|
||||
case 1:
|
||||
return file->author();
|
||||
case 2:
|
||||
return QString("%1 kB").arg(int((file->size() + 1023) / 1024));
|
||||
case 3:
|
||||
//return file->modified().toString(Qt::TextDate);
|
||||
return file->modified().toString(Qt::ISODate);
|
||||
case 4:
|
||||
return file->accessed().toString(Qt::TextDate);
|
||||
case 5:
|
||||
return file->version();
|
||||
case 6:
|
||||
return file->path();
|
||||
case 7:
|
||||
return file->masters().join(", ");
|
||||
case 8:
|
||||
return file->description();
|
||||
}
|
||||
}
|
||||
|
||||
case Qt::TextAlignmentRole: {
|
||||
switch (column) {
|
||||
case 0:
|
||||
case 1:
|
||||
return Qt::AlignLeft + Qt::AlignVCenter;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
return Qt::AlignRight + Qt::AlignVCenter;
|
||||
default:
|
||||
return Qt::AlignLeft + Qt::AlignVCenter;
|
||||
}
|
||||
}
|
||||
|
||||
case Qt::CheckStateRole: {
|
||||
if (column != 0)
|
||||
return QVariant();
|
||||
return mCheckStates[file->fileName()];
|
||||
}
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
if (column != 0)
|
||||
return QVariant();
|
||||
|
||||
if (file->version() == 0.0f)
|
||||
return QVariant(); // Data not set
|
||||
|
||||
QString tooltip =
|
||||
QString("<b>Author:</b> %1<br/> \
|
||||
<b>Version:</b> %2<br/> \
|
||||
<br/><b>Description:</b><br/>%3<br/> \
|
||||
<br/><b>Dependencies: </b>%4<br/>")
|
||||
.arg(file->author())
|
||||
.arg(QString::number(file->version()))
|
||||
.arg(file->description())
|
||||
.arg(file->masters().join(", "));
|
||||
|
||||
|
||||
return tooltip;
|
||||
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
EsmFile *file = item(index.row());
|
||||
|
||||
if (!file)
|
||||
return Qt::NoItemFlags;
|
||||
|
||||
if (mAvailableFiles.contains(file->fileName())) {
|
||||
if (index.column() == 0) {
|
||||
return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
} else {
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
} else {
|
||||
if (index.column() == 0) {
|
||||
return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable;
|
||||
} else {
|
||||
return Qt::NoItemFlags | Qt::ItemIsSelectable;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QVariant DataFilesModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
if (orientation == Qt::Horizontal) {
|
||||
switch (section) {
|
||||
case 0: return tr("Name");
|
||||
case 1: return tr("Author");
|
||||
case 2: return tr("Size");
|
||||
case 3: return tr("Modified");
|
||||
case 4: return tr("Accessed");
|
||||
case 5: return tr("Version");
|
||||
case 6: return tr("Path");
|
||||
case 7: return tr("Masters");
|
||||
case 8: return tr("Description");
|
||||
}
|
||||
} else {
|
||||
// Show row numbers
|
||||
return ++section;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return false;
|
||||
|
||||
if (role == Qt::CheckStateRole) {
|
||||
|
||||
emit layoutAboutToBeChanged();
|
||||
|
||||
QString name = item(index.row())->fileName();
|
||||
mCheckStates[name] = static_cast<Qt::CheckState>(value.toInt());
|
||||
|
||||
emit checkedItemsChanged(checkedItems(), uncheckedItems());
|
||||
emit layoutChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DataFilesModel::sort(int column, Qt::SortOrder order)
|
||||
{
|
||||
// TODO: Make this more efficient
|
||||
emit layoutAboutToBeChanged();
|
||||
|
||||
QList<EsmFile *> sortedFiles;
|
||||
|
||||
QMultiMap<QString, QString> timestamps;
|
||||
|
||||
foreach (EsmFile *file, mFiles)
|
||||
timestamps.insert(file->modified().toString(Qt::ISODate), file->fileName());
|
||||
|
||||
QMapIterator<QString, QString> ti(timestamps);
|
||||
|
||||
while (ti.hasNext()) {
|
||||
ti.next();
|
||||
|
||||
QModelIndex index = indexFromItem(findItem(ti.value()));
|
||||
|
||||
if (!index.isValid())
|
||||
continue;
|
||||
|
||||
EsmFile *file = item(index.row());
|
||||
|
||||
if (!file)
|
||||
continue;
|
||||
|
||||
sortedFiles.append(file);
|
||||
}
|
||||
|
||||
mFiles.clear();
|
||||
mFiles = sortedFiles;
|
||||
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
void DataFilesModel::addFile(EsmFile *file)
|
||||
{
|
||||
emit beginInsertRows(QModelIndex(), mFiles.count(), mFiles.count());
|
||||
mFiles.append(file);
|
||||
emit endInsertRows();
|
||||
}
|
||||
|
||||
void DataFilesModel::addMasters(const QString &path)
|
||||
{
|
||||
QDir dir(path);
|
||||
dir.setNameFilters(QStringList(QLatin1String("*.esp")));
|
||||
|
||||
// Read the dependencies from the plugins
|
||||
foreach (const QString &path, dir.entryList()) {
|
||||
try {
|
||||
ESM::ESMReader fileReader;
|
||||
fileReader.setEncoding(mEncoding.toStdString());
|
||||
fileReader.open(dir.absoluteFilePath(path).toStdString());
|
||||
|
||||
ESM::ESMReader::MasterList mlist = fileReader.getMasters();
|
||||
|
||||
for (unsigned int i = 0; i < mlist.size(); ++i) {
|
||||
QString master = QString::fromStdString(mlist[i].name);
|
||||
|
||||
// Add the plugin to the internal dependency map
|
||||
mDependencies[master].append(path);
|
||||
|
||||
// Don't add esps
|
||||
if (master.endsWith(".esp", Qt::CaseInsensitive))
|
||||
continue;
|
||||
|
||||
QFileInfo info(dir.absoluteFilePath(master));
|
||||
|
||||
EsmFile *file = new EsmFile(master);
|
||||
file->setDates(info.lastModified(), info.lastRead());
|
||||
|
||||
// Add the master to the table
|
||||
if (findItem(master) == 0)
|
||||
addFile(file);
|
||||
|
||||
|
||||
}
|
||||
|
||||
} catch(std::runtime_error &e) {
|
||||
// An error occurred while reading the .esp
|
||||
qWarning() << "Error reading esp: " << e.what();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// See if the masters actually exist in the filesystem
|
||||
dir.setNameFilters(QStringList(QLatin1String("*.esm")));
|
||||
|
||||
foreach (const QString &path, dir.entryList()) {
|
||||
QFileInfo info(dir.absoluteFilePath(path));
|
||||
|
||||
if (findItem(path) == 0) {
|
||||
EsmFile *file = new EsmFile(path);
|
||||
file->setDates(info.lastModified(), info.lastRead());
|
||||
|
||||
addFile(file);
|
||||
}
|
||||
|
||||
// Make the master selectable
|
||||
mAvailableFiles.append(path);
|
||||
}
|
||||
}
|
||||
|
||||
void DataFilesModel::addPlugins(const QString &path)
|
||||
{
|
||||
QDir dir(path);
|
||||
dir.setNameFilters(QStringList(QLatin1String("*.esp")));
|
||||
|
||||
foreach (const QString &path, dir.entryList()) {
|
||||
QFileInfo info(dir.absoluteFilePath(path));
|
||||
EsmFile *file = new EsmFile(path);
|
||||
|
||||
try {
|
||||
ESM::ESMReader fileReader;
|
||||
fileReader.setEncoding(mEncoding.toStdString());
|
||||
fileReader.open(dir.absoluteFilePath(path).toStdString());
|
||||
|
||||
ESM::ESMReader::MasterList mlist = fileReader.getMasters();
|
||||
QStringList masters;
|
||||
|
||||
for (unsigned int i = 0; i < mlist.size(); ++i) {
|
||||
QString master = QString::fromStdString(mlist[i].name);
|
||||
masters.append(master);
|
||||
|
||||
// Add the plugin to the internal dependency map
|
||||
mDependencies[master].append(path);
|
||||
}
|
||||
|
||||
file->setAuthor(QString::fromStdString(fileReader.getAuthor()));
|
||||
file->setSize(info.size());
|
||||
file->setDates(info.lastModified(), info.lastRead());
|
||||
file->setVersion(fileReader.getFVer());
|
||||
file->setPath(info.absoluteFilePath());
|
||||
file->setMasters(masters);
|
||||
file->setDescription(QString::fromStdString(fileReader.getDesc()));
|
||||
|
||||
|
||||
// Put the file in the table
|
||||
addFile(file);
|
||||
} catch(std::runtime_error &e) {
|
||||
// An error occurred while reading the .esp
|
||||
qWarning() << "Error reading esp: " << e.what();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex DataFilesModel::indexFromItem(EsmFile *item) const
|
||||
{
|
||||
if (item)
|
||||
return createIndex(mFiles.indexOf(item), 0);
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
EsmFile* DataFilesModel::findItem(const QString &name)
|
||||
{
|
||||
QList<EsmFile *>::ConstIterator it;
|
||||
QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
|
||||
|
||||
int i = 0;
|
||||
for (it = mFiles.constBegin(); it != itEnd; ++it) {
|
||||
EsmFile *file = item(i);
|
||||
++i;
|
||||
|
||||
if (name == file->fileName())
|
||||
return file;
|
||||
}
|
||||
|
||||
// Not found
|
||||
return 0;
|
||||
}
|
||||
|
||||
EsmFile* DataFilesModel::item(int row) const
|
||||
{
|
||||
if (row >= 0 && row < mFiles.count())
|
||||
return mFiles.at(row);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
QStringList DataFilesModel::checkedItems()
|
||||
{
|
||||
QStringList list;
|
||||
|
||||
QList<EsmFile *>::ConstIterator it;
|
||||
QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
|
||||
|
||||
int i = 0;
|
||||
for (it = mFiles.constBegin(); it != itEnd; ++it) {
|
||||
EsmFile *file = item(i);
|
||||
++i;
|
||||
|
||||
QString name = file->fileName();
|
||||
|
||||
// Only add the items that are in the checked list and available
|
||||
if (mCheckStates[name] == Qt::Checked && mAvailableFiles.contains(name))
|
||||
list << name;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void DataFilesModel::uncheckAll()
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
mCheckStates.clear();
|
||||
emit layoutChanged();
|
||||
}
|
||||
|
||||
QStringList DataFilesModel::uncheckedItems()
|
||||
{
|
||||
QStringList list;
|
||||
QStringList checked = checkedItems();
|
||||
|
||||
QList<EsmFile *>::ConstIterator it;
|
||||
QList<EsmFile *>::ConstIterator itEnd = mFiles.constEnd();
|
||||
|
||||
int i = 0;
|
||||
for (it = mFiles.constBegin(); it != itEnd; ++it) {
|
||||
EsmFile *file = item(i);
|
||||
++i;
|
||||
|
||||
// Add the items that are not in the checked list
|
||||
if (!checked.contains(file->fileName()))
|
||||
list << file->fileName();
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void DataFilesModel::slotcheckedItemsChanged(const QStringList &checkedItems, const QStringList &unCheckedItems)
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
|
||||
QStringList list;
|
||||
|
||||
foreach (const QString &file, checkedItems) {
|
||||
list << mDependencies[file];
|
||||
}
|
||||
|
||||
foreach (const QString &file, unCheckedItems) {
|
||||
foreach (const QString &remove, mDependencies[file]) {
|
||||
list.removeAll(remove);
|
||||
}
|
||||
}
|
||||
|
||||
mAvailableFiles.clear();
|
||||
mAvailableFiles.append(list);
|
||||
|
||||
emit layoutChanged();
|
||||
}
|
71
apps/launcher/model/datafilesmodel.hpp
Normal file
71
apps/launcher/model/datafilesmodel.hpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
#ifndef DATAFILESMODEL_HPP
|
||||
#define DATAFILESMODEL_HPP
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
|
||||
|
||||
class EsmFile;
|
||||
|
||||
class DataFilesModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DataFilesModel(QObject *parent = 0);
|
||||
virtual ~DataFilesModel();
|
||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
bool moveRow(int oldrow, int row, const QModelIndex &parent = QModelIndex());
|
||||
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
|
||||
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
|
||||
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
|
||||
|
||||
inline QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const
|
||||
{ return QAbstractTableModel::index(row, column, parent); }
|
||||
|
||||
void setEncoding(const QString &encoding);
|
||||
|
||||
void addFile(EsmFile *file);
|
||||
|
||||
void addMasters(const QString &path);
|
||||
void addPlugins(const QString &path);
|
||||
|
||||
void uncheckAll();
|
||||
|
||||
QStringList checkedItems();
|
||||
QStringList uncheckedItems();
|
||||
|
||||
Qt::CheckState checkState(const QModelIndex &index);
|
||||
void setCheckState(const QModelIndex &index, Qt::CheckState state);
|
||||
|
||||
QModelIndex indexFromItem(EsmFile *item) const;
|
||||
EsmFile* findItem(const QString &name);
|
||||
EsmFile* item(int row) const;
|
||||
|
||||
signals:
|
||||
void checkedItemsChanged(const QStringList checkedItems, const QStringList unCheckedItems);
|
||||
|
||||
public slots:
|
||||
void slotcheckedItemsChanged(const QStringList &checkedItems, const QStringList &unCheckedItems);
|
||||
|
||||
private:
|
||||
QList<EsmFile *> mFiles;
|
||||
QStringList mAvailableFiles;
|
||||
|
||||
QHash<QString, QStringList> mDependencies;
|
||||
QHash<QString, Qt::CheckState> mCheckStates;
|
||||
|
||||
QString mEncoding;
|
||||
|
||||
};
|
||||
|
||||
#endif // DATAFILESMODEL_HPP
|
50
apps/launcher/model/esm/esmfile.cpp
Normal file
50
apps/launcher/model/esm/esmfile.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include "esmfile.hpp"
|
||||
|
||||
EsmFile::EsmFile(QString fileName, ModelItem *parent)
|
||||
: ModelItem(parent)
|
||||
{
|
||||
mFileName = fileName;
|
||||
mSize = 0;
|
||||
mVersion = 0.0f;
|
||||
}
|
||||
|
||||
void EsmFile::setFileName(const QString &fileName)
|
||||
{
|
||||
mFileName = fileName;
|
||||
}
|
||||
|
||||
void EsmFile::setAuthor(const QString &author)
|
||||
{
|
||||
mAuthor = author;
|
||||
}
|
||||
|
||||
void EsmFile::setSize(const int size)
|
||||
{
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
void EsmFile::setDates(const QDateTime &modified, const QDateTime &accessed)
|
||||
{
|
||||
mModified = modified;
|
||||
mAccessed = accessed;
|
||||
}
|
||||
|
||||
void EsmFile::setVersion(float version)
|
||||
{
|
||||
mVersion = version;
|
||||
}
|
||||
|
||||
void EsmFile::setPath(const QString &path)
|
||||
{
|
||||
mPath = path;
|
||||
}
|
||||
|
||||
void EsmFile::setMasters(const QStringList &masters)
|
||||
{
|
||||
mMasters = masters;
|
||||
}
|
||||
|
||||
void EsmFile::setDescription(const QString &description)
|
||||
{
|
||||
mDescription = description;
|
||||
}
|
54
apps/launcher/model/esm/esmfile.hpp
Normal file
54
apps/launcher/model/esm/esmfile.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef ESMFILE_HPP
|
||||
#define ESMFILE_HPP
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QStringList>
|
||||
|
||||
#include "../modelitem.hpp"
|
||||
|
||||
class EsmFile : public ModelItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString filename READ fileName)
|
||||
|
||||
public:
|
||||
EsmFile(QString fileName = QString(), ModelItem *parent = 0);
|
||||
|
||||
~EsmFile()
|
||||
{}
|
||||
|
||||
void setFileName(const QString &fileName);
|
||||
void setAuthor(const QString &author);
|
||||
void setSize(const int size);
|
||||
void setDates(const QDateTime &modified, const QDateTime &accessed);
|
||||
void setVersion(const float version);
|
||||
void setPath(const QString &path);
|
||||
void setMasters(const QStringList &masters);
|
||||
void setDescription(const QString &description);
|
||||
|
||||
inline QString fileName() { return mFileName; }
|
||||
inline QString author() { return mAuthor; }
|
||||
inline int size() { return mSize; }
|
||||
inline QDateTime modified() { return mModified; }
|
||||
inline QDateTime accessed() { return mAccessed; }
|
||||
inline float version() { return mVersion; }
|
||||
inline QString path() { return mPath; }
|
||||
inline QStringList masters() { return mMasters; }
|
||||
inline QString description() { return mDescription; }
|
||||
|
||||
|
||||
private:
|
||||
QString mFileName;
|
||||
QString mAuthor;
|
||||
int mSize;
|
||||
QDateTime mModified;
|
||||
QDateTime mAccessed;
|
||||
float mVersion;
|
||||
QString mPath;
|
||||
QStringList mMasters;
|
||||
QString mDescription;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
57
apps/launcher/model/modelitem.cpp
Normal file
57
apps/launcher/model/modelitem.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "modelitem.hpp"
|
||||
|
||||
ModelItem::ModelItem(ModelItem *parent)
|
||||
: mParentItem(parent)
|
||||
, QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ModelItem::~ModelItem()
|
||||
{
|
||||
qDeleteAll(mChildItems);
|
||||
}
|
||||
|
||||
|
||||
ModelItem *ModelItem::parent()
|
||||
{
|
||||
return mParentItem;
|
||||
}
|
||||
|
||||
int ModelItem::row() const
|
||||
{
|
||||
if (mParentItem)
|
||||
return 1;
|
||||
//return mParentItem->childRow(const_cast<ModelItem*>(this));
|
||||
//return mParentItem->mChildItems.indexOf(const_cast<ModelItem*>(this));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int ModelItem::childCount() const
|
||||
{
|
||||
return mChildItems.count();
|
||||
}
|
||||
|
||||
int ModelItem::childRow(ModelItem *child) const
|
||||
{
|
||||
Q_ASSERT(child);
|
||||
|
||||
return mChildItems.indexOf(child);
|
||||
}
|
||||
|
||||
ModelItem *ModelItem::child(int row)
|
||||
{
|
||||
return mChildItems.value(row);
|
||||
}
|
||||
|
||||
|
||||
void ModelItem::appendChild(ModelItem *item)
|
||||
{
|
||||
mChildItems.append(item);
|
||||
}
|
||||
|
||||
void ModelItem::removeChild(int row)
|
||||
{
|
||||
mChildItems.removeAt(row);
|
||||
}
|
32
apps/launcher/model/modelitem.hpp
Normal file
32
apps/launcher/model/modelitem.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef MODELITEM_HPP
|
||||
#define MODELITEM_HPP
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
|
||||
class ModelItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModelItem(ModelItem *parent = 0);
|
||||
~ModelItem();
|
||||
|
||||
ModelItem *parent();
|
||||
int row() const;
|
||||
|
||||
int childCount() const;
|
||||
int childRow(ModelItem *child) const;
|
||||
ModelItem *child(int row);
|
||||
|
||||
void appendChild(ModelItem *child);
|
||||
void removeChild(int row);
|
||||
|
||||
//virtual bool acceptChild(ModelItem *child);
|
||||
|
||||
protected:
|
||||
ModelItem *mParentItem;
|
||||
QList<ModelItem*> mChildItems;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,149 +0,0 @@
|
|||
#include <QMimeData>
|
||||
#include <QBitArray>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "pluginsmodel.hpp"
|
||||
|
||||
PluginsModel::PluginsModel(QObject *parent) : QStandardItemModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void decodeDataRecursive(QDataStream &stream, QStandardItem *item)
|
||||
{
|
||||
int colCount, childCount;
|
||||
stream >> *item;
|
||||
stream >> colCount >> childCount;
|
||||
item->setColumnCount(colCount);
|
||||
|
||||
int childPos = childCount;
|
||||
|
||||
while(childPos > 0) {
|
||||
childPos--;
|
||||
QStandardItem *child = new QStandardItem();
|
||||
decodeDataRecursive(stream, child);
|
||||
item->setChild( childPos / colCount, childPos % colCount, child);
|
||||
}
|
||||
}
|
||||
|
||||
bool PluginsModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent)
|
||||
{
|
||||
// Code largely based on QStandardItemModel::dropMimeData
|
||||
|
||||
// check if the action is supported
|
||||
if (!data || !(action == Qt::CopyAction || action == Qt::MoveAction))
|
||||
return false;
|
||||
|
||||
// check if the format is supported
|
||||
QString format = QLatin1String("application/x-qstandarditemmodeldatalist");
|
||||
if (!data->hasFormat(format))
|
||||
return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
|
||||
|
||||
if (row > rowCount(parent))
|
||||
row = rowCount(parent);
|
||||
if (row == -1)
|
||||
row = rowCount(parent);
|
||||
if (column == -1)
|
||||
column = 0;
|
||||
|
||||
// decode and insert
|
||||
QByteArray encoded = data->data(format);
|
||||
QDataStream stream(&encoded, QIODevice::ReadOnly);
|
||||
|
||||
|
||||
//code based on QAbstractItemModel::decodeData
|
||||
// adapted to work with QStandardItem
|
||||
int top = std::numeric_limits<int>::max();
|
||||
int left = std::numeric_limits<int>::max();
|
||||
int bottom = 0;
|
||||
int right = 0;
|
||||
QVector<int> rows, columns;
|
||||
QVector<QStandardItem *> items;
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
int r, c;
|
||||
QStandardItem *item = new QStandardItem();
|
||||
stream >> r >> c;
|
||||
decodeDataRecursive(stream, item);
|
||||
|
||||
rows.append(r);
|
||||
columns.append(c);
|
||||
items.append(item);
|
||||
top = qMin(r, top);
|
||||
left = qMin(c, left);
|
||||
bottom = qMax(r, bottom);
|
||||
right = qMax(c, right);
|
||||
}
|
||||
|
||||
// insert the dragged items into the table, use a bit array to avoid overwriting items,
|
||||
// since items from different tables can have the same row and column
|
||||
int dragRowCount = 0;
|
||||
int dragColumnCount = right - left + 1;
|
||||
|
||||
// Compute the number of continuous rows upon insertion and modify the rows to match
|
||||
QVector<int> rowsToInsert(bottom + 1);
|
||||
for (int i = 0; i < rows.count(); ++i)
|
||||
rowsToInsert[rows.at(i)] = 1;
|
||||
for (int i = 0; i < rowsToInsert.count(); ++i) {
|
||||
if (rowsToInsert[i] == 1){
|
||||
rowsToInsert[i] = dragRowCount;
|
||||
++dragRowCount;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < rows.count(); ++i)
|
||||
rows[i] = top + rowsToInsert[rows[i]];
|
||||
|
||||
QBitArray isWrittenTo(dragRowCount * dragColumnCount);
|
||||
|
||||
// make space in the table for the dropped data
|
||||
int colCount = columnCount(parent);
|
||||
if (colCount < dragColumnCount + column) {
|
||||
insertColumns(colCount, dragColumnCount + column - colCount, parent);
|
||||
colCount = columnCount(parent);
|
||||
}
|
||||
insertRows(row, dragRowCount, parent);
|
||||
|
||||
row = qMax(0, row);
|
||||
column = qMax(0, column);
|
||||
|
||||
QStandardItem *parentItem = itemFromIndex (parent);
|
||||
if (!parentItem)
|
||||
parentItem = invisibleRootItem();
|
||||
|
||||
QVector<QPersistentModelIndex> newIndexes(items.size());
|
||||
// set the data in the table
|
||||
for (int j = 0; j < items.size(); ++j) {
|
||||
int relativeRow = rows.at(j) - top;
|
||||
int relativeColumn = columns.at(j) - left;
|
||||
int destinationRow = relativeRow + row;
|
||||
int destinationColumn = relativeColumn + column;
|
||||
int flat = (relativeRow * dragColumnCount) + relativeColumn;
|
||||
// if the item was already written to, or we just can't fit it in the table, create a new row
|
||||
if (destinationColumn >= colCount || isWrittenTo.testBit(flat)) {
|
||||
destinationColumn = qBound(column, destinationColumn, colCount - 1);
|
||||
destinationRow = row + dragRowCount;
|
||||
insertRows(row + dragRowCount, 1, parent);
|
||||
flat = (dragRowCount * dragColumnCount) + relativeColumn;
|
||||
isWrittenTo.resize(++dragRowCount * dragColumnCount);
|
||||
}
|
||||
if (!isWrittenTo.testBit(flat)) {
|
||||
newIndexes[j] = index(destinationRow, destinationColumn, parentItem->index());
|
||||
isWrittenTo.setBit(flat);
|
||||
}
|
||||
}
|
||||
|
||||
for(int k = 0; k < newIndexes.size(); k++) {
|
||||
if (newIndexes.at(k).isValid()) {
|
||||
parentItem->setChild(newIndexes.at(k).row(), newIndexes.at(k).column(), items.at(k));
|
||||
} else {
|
||||
delete items.at(k);
|
||||
}
|
||||
}
|
||||
|
||||
// The important part, tell the view what is dropped
|
||||
emit indexesDropped(newIndexes);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef PLUGINSMODEL_H
|
||||
#define PLUGINSMODEL_H
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
class PluginsModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PluginsModel(QObject *parent = 0);
|
||||
~PluginsModel() {};
|
||||
|
||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
|
||||
|
||||
signals:
|
||||
void indexesDropped(QVector<QPersistentModelIndex> indexes);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,41 +0,0 @@
|
|||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "pluginsview.hpp"
|
||||
|
||||
PluginsView::PluginsView(QWidget *parent) : QTableView(parent)
|
||||
{
|
||||
setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
setAlternatingRowColors(true);
|
||||
setDragEnabled(true);
|
||||
setDragDropMode(QAbstractItemView::InternalMove);
|
||||
setDropIndicatorShown(true);
|
||||
setDragDropOverwriteMode(false);
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
}
|
||||
|
||||
void PluginsView::startDrag(Qt::DropActions supportedActions)
|
||||
{
|
||||
selectionModel()->select( selectionModel()->selection(),
|
||||
QItemSelectionModel::Select | QItemSelectionModel::Rows );
|
||||
QAbstractItemView::startDrag( supportedActions );
|
||||
}
|
||||
|
||||
void PluginsView::setModel(QSortFilterProxyModel *model)
|
||||
{
|
||||
QTableView::setModel(model);
|
||||
|
||||
qRegisterMetaType< QVector<QPersistentModelIndex> >();
|
||||
|
||||
connect(model->sourceModel(), SIGNAL(indexesDropped(QVector<QPersistentModelIndex>)),
|
||||
this, SLOT(selectIndexes(QVector<QPersistentModelIndex>)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void PluginsView::selectIndexes( QVector<QPersistentModelIndex> aIndexes )
|
||||
{
|
||||
selectionModel()->clearSelection();
|
||||
foreach( QPersistentModelIndex pIndex, aIndexes )
|
||||
selectionModel()->select( pIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows );
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
#ifndef PLUGINSVIEW_H
|
||||
#define PLUGINSVIEW_H
|
||||
|
||||
#include <QTableView>
|
||||
|
||||
#include "pluginsmodel.hpp"
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
|
||||
class PluginsView : public QTableView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PluginsView(QWidget *parent = 0);
|
||||
|
||||
PluginsModel* model() const
|
||||
{ return qobject_cast<PluginsModel*>(QAbstractItemView::model()); }
|
||||
|
||||
void startDrag(Qt::DropActions supportedActions);
|
||||
void setModel(QSortFilterProxyModel *model);
|
||||
|
||||
public slots:
|
||||
void selectIndexes(QVector<QPersistentModelIndex> aIndexes);
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QVector<QPersistentModelIndex>);
|
||||
|
||||
#endif
|
52
apps/launcher/utils/profilescombobox.cpp
Normal file
52
apps/launcher/utils/profilescombobox.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include <QRegExpValidator>
|
||||
#include <QLineEdit>
|
||||
#include <QString>
|
||||
|
||||
#include "profilescombobox.hpp"
|
||||
|
||||
ProfilesComboBox::ProfilesComboBox(QWidget *parent) :
|
||||
QComboBox(parent)
|
||||
{
|
||||
mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
|
||||
|
||||
setEditable(true);
|
||||
setValidator(mValidator);
|
||||
setCompleter(0);
|
||||
|
||||
connect(this, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(slotIndexChanged(int)));
|
||||
connect(lineEdit(), SIGNAL(returnPressed()), this,
|
||||
SLOT(slotReturnPressed()));
|
||||
}
|
||||
|
||||
void ProfilesComboBox::setEditEnabled(bool editable)
|
||||
{
|
||||
if (!editable)
|
||||
return setEditable(false);
|
||||
|
||||
// Reset the completer and validator
|
||||
setEditable(true);
|
||||
setValidator(mValidator);
|
||||
setCompleter(0);
|
||||
}
|
||||
|
||||
void ProfilesComboBox::slotReturnPressed()
|
||||
{
|
||||
QString current = currentText();
|
||||
QString previous = itemText(currentIndex());
|
||||
|
||||
if (findText(current) != -1)
|
||||
return;
|
||||
|
||||
setItemText(currentIndex(), current);
|
||||
emit(profileRenamed(previous, current));
|
||||
}
|
||||
|
||||
void ProfilesComboBox::slotIndexChanged(int index)
|
||||
{
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
emit(profileChanged(mOldProfile, currentText()));
|
||||
mOldProfile = itemText(index);
|
||||
}
|
30
apps/launcher/utils/profilescombobox.hpp
Normal file
30
apps/launcher/utils/profilescombobox.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef PROFILESCOMBOBOX_HPP
|
||||
#define PROFILESCOMBOBOX_HPP
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
class QString;
|
||||
|
||||
class QRegExpValidator;
|
||||
|
||||
class ProfilesComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ProfilesComboBox(QWidget *parent = 0);
|
||||
void setEditEnabled(bool editable);
|
||||
|
||||
signals:
|
||||
void profileChanged(const QString &previous, const QString ¤t);
|
||||
void profileRenamed(const QString &oldName, const QString &newName);
|
||||
|
||||
private slots:
|
||||
void slotReturnPressed();
|
||||
void slotIndexChanged(int index);
|
||||
|
||||
private:
|
||||
QString mOldProfile;
|
||||
QRegExpValidator *mValidator;
|
||||
};
|
||||
|
||||
#endif // PROFILESCOMBOBOX_HPP
|
61
apps/launcher/utils/textinputdialog.cpp
Normal file
61
apps/launcher/utils/textinputdialog.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QDebug>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QValidator>
|
||||
|
||||
#include "lineedit.hpp"
|
||||
|
||||
#include "textinputdialog.hpp"
|
||||
|
||||
TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWidget *parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
mButtonBox = new QDialogButtonBox(this);
|
||||
mButtonBox->addButton(QDialogButtonBox::Ok);
|
||||
mButtonBox->addButton(QDialogButtonBox::Cancel);
|
||||
|
||||
setMaximumHeight(height());
|
||||
setOkButtonEnabled(false);
|
||||
setModal(true);
|
||||
|
||||
// Messageboxes on mac have no title
|
||||
#ifndef Q_OS_MAC
|
||||
setWindowTitle(title);
|
||||
#else
|
||||
Q_UNUSED(title);
|
||||
#endif
|
||||
|
||||
QLabel *label = new QLabel(this);
|
||||
label->setText(text);
|
||||
|
||||
// Line edit
|
||||
QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
|
||||
mLineEdit = new LineEdit(this);
|
||||
mLineEdit->setValidator(validator);
|
||||
mLineEdit->setCompleter(0);
|
||||
|
||||
QVBoxLayout *dialogLayout = new QVBoxLayout(this);
|
||||
dialogLayout->addWidget(label);
|
||||
dialogLayout->addWidget(mLineEdit);
|
||||
dialogLayout->addWidget(mButtonBox);
|
||||
|
||||
connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
}
|
||||
|
||||
int TextInputDialog::exec()
|
||||
{
|
||||
mLineEdit->clear();
|
||||
mLineEdit->setFocus();
|
||||
return QDialog::exec();
|
||||
}
|
||||
|
||||
void TextInputDialog::setOkButtonEnabled(bool enabled)
|
||||
{
|
||||
|
||||
QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok);
|
||||
okButton->setEnabled(enabled);
|
||||
}
|
28
apps/launcher/utils/textinputdialog.hpp
Normal file
28
apps/launcher/utils/textinputdialog.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef TEXTINPUTDIALOG_HPP
|
||||
#define TEXTINPUTDIALOG_HPP
|
||||
|
||||
#include <QDialog>
|
||||
//#include "lineedit.hpp"
|
||||
|
||||
class QDialogButtonBox;
|
||||
class LineEdit;
|
||||
|
||||
class TextInputDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TextInputDialog(const QString& title, const QString &text, QWidget *parent = 0);
|
||||
inline LineEdit *lineEdit() { return mLineEdit; }
|
||||
void setOkButtonEnabled(bool enabled);
|
||||
|
||||
LineEdit *mLineEdit;
|
||||
|
||||
int exec();
|
||||
|
||||
private:
|
||||
QDialogButtonBox *mButtonBox;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // TEXTINPUTDIALOG_HPP
|
|
@ -78,7 +78,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) {
|
|||
|
||||
multistrmap::iterator it;
|
||||
if((it = map.find(key)) == map.end()) {
|
||||
map.insert( std::make_pair<std::string, std::vector<std::string> > (key, std::vector<std::string>() ) );
|
||||
map.insert( std::make_pair (key, std::vector<std::string>() ) );
|
||||
}
|
||||
map[key].push_back(value);
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) {
|
|||
|
||||
multistrmap::iterator it;
|
||||
if((it = map.find(key)) == map.end()) {
|
||||
map.insert( std::make_pair<std::string, std::vector<std::string> > (key, std::vector<std::string>() ) );
|
||||
map.insert( std::make_pair (key, std::vector<std::string>() ) );
|
||||
}
|
||||
map[key].push_back(value);
|
||||
}
|
||||
|
@ -152,12 +152,12 @@ void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) {
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void MwIniImporter::insertMultistrmap(multistrmap &cfg, std::string key, std::string value) {
|
||||
multistrmap::iterator it = cfg.find(key);
|
||||
if(it == cfg.end()) {
|
||||
cfg.insert(std::make_pair<std::string, std::vector<std::string> >(key, std::vector<std::string>() ));
|
||||
cfg.insert(std::make_pair (key, std::vector<std::string>() ));
|
||||
}
|
||||
cfg[key].push_back(value);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ add_openmw_dir (mwgui
|
|||
map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list
|
||||
formatting inventorywindow container hud countdialog tradewindow settingswindow
|
||||
confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu
|
||||
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog
|
||||
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
|
||||
enchantingdialog trainingwindow travelwindow
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
|
@ -61,7 +62,7 @@ add_openmw_dir (mwclass
|
|||
|
||||
add_openmw_dir (mwmechanics
|
||||
mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells
|
||||
activespells npcstats aipackage aisequence
|
||||
activespells npcstats aipackage aisequence alchemy
|
||||
)
|
||||
|
||||
add_openmw_dir (mwbase
|
||||
|
|
|
@ -101,7 +101,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
MWBase::Environment::get().getWorld()->doPhysics (movement, mEnvironment.getFrameDuration());
|
||||
|
||||
// update world
|
||||
MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame);
|
||||
MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame, MWBase::Environment::get().getWindowManager()->isGuiMode());
|
||||
|
||||
// update GUI
|
||||
Ogre::RenderWindow* window = mOgre->getWindow();
|
||||
|
@ -163,9 +163,8 @@ void OMW::Engine::loadBSA()
|
|||
std::cout << "Data dir " << dataDirectory << std::endl;
|
||||
Bsa::addDir(dataDirectory, mFSStrict);
|
||||
|
||||
// Workaround: Mygui does not find textures in non-BSA subfolders, _unless_ they are explicitely added like this
|
||||
// For splash screens, this is OK to do, but eventually we will need an investigation why this is necessary
|
||||
Bsa::addDir(dataDirectory + "/Splash", mFSStrict);
|
||||
// Workaround until resource listing capabilities are added to DirArchive, we need those to list available splash screens
|
||||
addResourcesDirectory (dataDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,21 +436,10 @@ void OMW::Engine::activate()
|
|||
if (handle.empty())
|
||||
return;
|
||||
|
||||
// the faced handle is not updated immediately, so on a cell change it might
|
||||
// point to an object that doesn't exist anymore
|
||||
// therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case
|
||||
MWWorld::Ptr ptr;
|
||||
try
|
||||
{
|
||||
ptr = MWBase::Environment::get().getWorld()->getPtrViaHandle (handle);
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle (handle);
|
||||
|
||||
if (ptr.isEmpty())
|
||||
return;
|
||||
}
|
||||
catch (std::runtime_error&)
|
||||
{
|
||||
if (ptr.isEmpty())
|
||||
return;
|
||||
}
|
||||
|
||||
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ void validate(boost::any &v, std::vector<std::string> const &tokens, FallbackMap
|
|||
|
||||
if((mapIt = map->mMap.find(key)) == map->mMap.end())
|
||||
{
|
||||
map->mMap.insert(std::make_pair<std::string,std::string>(key,value));
|
||||
map->mMap.insert(std::make_pair (key,value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ namespace MWBase
|
|||
|
||||
virtual void addActor (const MWWorld::Ptr& ptr) = 0;
|
||||
///< Register an actor for stats management
|
||||
///
|
||||
/// \note Dead actors are ignored.
|
||||
|
||||
virtual void removeActor (const MWWorld::Ptr& ptr) = 0;
|
||||
///< Deregister an actor for stats management
|
||||
|
@ -74,6 +76,9 @@ namespace MWBase
|
|||
|
||||
virtual void restoreDynamicStats() = 0;
|
||||
///< If the player is sleeping, this should be called every hour.
|
||||
|
||||
virtual int countDeaths (const std::string& id) const = 0;
|
||||
///< Return the number of deaths for actors with the given ID.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace MWBase
|
|||
Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */
|
||||
Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */
|
||||
Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */
|
||||
Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position
|
||||
Play_NoTrack = 1<<2 /* (3D only) Play the sound at the given object's position
|
||||
* but do not keep it updated (the sound will not move with
|
||||
* the object and will not stop when the object is deleted. */
|
||||
};
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace MWGui
|
|||
class Console;
|
||||
class SpellWindow;
|
||||
class TradeWindow;
|
||||
class TravelWindow;
|
||||
class SpellBuyingWindow;
|
||||
class ConfirmationDialog;
|
||||
class CountDialog;
|
||||
|
@ -108,6 +109,7 @@ namespace MWBase
|
|||
virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0;
|
||||
virtual MWGui::TradeWindow* getTradeWindow() = 0;
|
||||
virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow() = 0;
|
||||
virtual MWGui::TravelWindow* getTravelWindow() = 0;
|
||||
virtual MWGui::SpellWindow* getSpellWindow() = 0;
|
||||
virtual MWGui::Console* getConsole() = 0;
|
||||
|
||||
|
@ -227,6 +229,10 @@ namespace MWBase
|
|||
|
||||
virtual bool getPlayerSleeping() = 0;
|
||||
virtual void wakeUpPlayer() = 0;
|
||||
|
||||
virtual void startSpellMaking(MWWorld::Ptr actor) = 0;
|
||||
virtual void startEnchanting(MWWorld::Ptr actor) = 0;
|
||||
virtual void startTraining(MWWorld::Ptr actor) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace ESM
|
|||
struct Cell;
|
||||
struct Class;
|
||||
struct Potion;
|
||||
struct Spell;
|
||||
}
|
||||
|
||||
namespace ESMS
|
||||
|
@ -142,6 +143,9 @@ namespace MWBase
|
|||
virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0;
|
||||
///< Return a pointer to a liveCellRef with the given Ogre handle.
|
||||
|
||||
virtual MWWorld::Ptr searchPtrViaHandle (const std::string& handle) = 0;
|
||||
///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found
|
||||
|
||||
/// \todo enable reference in the OGRE scene
|
||||
virtual void enable (const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
|
@ -235,6 +239,11 @@ namespace MWBase
|
|||
///< Create a new recrod (of type potion) in the ESM store.
|
||||
/// \return ID, pointer to created record
|
||||
|
||||
virtual std::pair<std::string, const ESM::Spell *> createRecord (const ESM::Spell& record)
|
||||
= 0;
|
||||
///< Create a new recrod (of type spell) in the ESM store.
|
||||
/// \return ID, pointer to created record
|
||||
|
||||
virtual std::pair<std::string, const ESM::Class *> createRecord (const ESM::Class& record)
|
||||
= 0;
|
||||
///< Create a new recrod (of type class) in the ESM store.
|
||||
|
@ -256,7 +265,7 @@ namespace MWBase
|
|||
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
|
||||
/// references that are currently not in the rendered scene should be ignored.
|
||||
|
||||
virtual void update (float duration) = 0;
|
||||
virtual void update (float duration, bool paused) = 0;
|
||||
|
||||
virtual bool placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY) = 0;
|
||||
///< place an object into the gameworld at the specified cursor position
|
||||
|
|
|
@ -30,9 +30,8 @@ namespace MWClass
|
|||
void Activator::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Activator::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
@ -94,7 +93,7 @@ namespace MWClass
|
|||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
MWWorld::Ptr
|
||||
Activator::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const
|
||||
{
|
||||
|
|
|
@ -33,9 +33,8 @@ namespace MWClass
|
|||
void Apparatus::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -36,9 +36,8 @@ namespace MWClass
|
|||
void Armor::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Armor::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -32,9 +32,8 @@ namespace MWClass
|
|||
void Book::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Book::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -34,9 +34,8 @@ namespace MWClass
|
|||
void Clothing::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Clothing::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -65,9 +65,8 @@ namespace MWClass
|
|||
void Container::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Container::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
@ -95,9 +94,15 @@ namespace MWClass
|
|||
bool needKey = ptr.getCellRef().mLockLevel>0;
|
||||
bool hasKey = false;
|
||||
std::string keyName;
|
||||
|
||||
// make key id lowercase
|
||||
std::string keyId = ptr.getCellRef().mKey;
|
||||
std::transform(keyId.begin(), keyId.end(), keyId.begin(), ::tolower);
|
||||
for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it)
|
||||
{
|
||||
if (it->getCellRef ().mRefID == ptr.getCellRef().mKey)
|
||||
std::string refId = it->getCellRef().mRefID;
|
||||
std::transform(refId.begin(), refId.end(), refId.begin(), ::tolower);
|
||||
if (refId == keyId)
|
||||
{
|
||||
hasKey = true;
|
||||
keyName = MWWorld::Class::get(*it).getName(*it);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/actionopen.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
|
@ -55,9 +56,9 @@ namespace MWClass
|
|||
data->mCreatureStats.getAttribute(5).set (ref->base->mData.mEndurance);
|
||||
data->mCreatureStats.getAttribute(6).set (ref->base->mData.mPersonality);
|
||||
data->mCreatureStats.getAttribute(7).set (ref->base->mData.mLuck);
|
||||
data->mCreatureStats.getHealth().set (ref->base->mData.mHealth);
|
||||
data->mCreatureStats.getMagicka().set (ref->base->mData.mMana);
|
||||
data->mCreatureStats.getFatigue().set (ref->base->mData.mFatigue);
|
||||
data->mCreatureStats.setHealth (ref->base->mData.mHealth);
|
||||
data->mCreatureStats.setMagicka (ref->base->mData.mMana);
|
||||
data->mCreatureStats.setFatigue (ref->base->mData.mFatigue);
|
||||
|
||||
data->mCreatureStats.setLevel(ref->base->mData.mLevel);
|
||||
|
||||
|
@ -93,9 +94,8 @@ namespace MWClass
|
|||
void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()){
|
||||
physics.insertActorPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addActor(ptr);
|
||||
MWBase::Environment::get().getMechanicsManager()->addActor (ptr);
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,10 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Creature::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const
|
||||
{
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead())
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionOpen(ptr));
|
||||
else
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Creature::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
|
@ -149,6 +152,14 @@ namespace MWClass
|
|||
return ref->base->mScript;
|
||||
}
|
||||
|
||||
bool Creature::isEssential (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->base->mFlags & ESM::Creature::Essential;
|
||||
}
|
||||
|
||||
void Creature::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Creature);
|
||||
|
|
|
@ -56,6 +56,9 @@ namespace MWClass
|
|||
///< Returns total weight of objects inside this object (including modifications from magic
|
||||
/// effects). Throws an exception, if the object can't hold other objects.
|
||||
|
||||
virtual bool isEssential (const MWWorld::Ptr& ptr) const;
|
||||
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
|
|
@ -35,9 +35,8 @@ namespace MWClass
|
|||
void Door::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Door::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
@ -81,9 +80,15 @@ namespace MWClass
|
|||
bool needKey = ptr.getCellRef().mLockLevel>0;
|
||||
bool hasKey = false;
|
||||
std::string keyName;
|
||||
|
||||
// make key id lowercase
|
||||
std::string keyId = ptr.getCellRef().mKey;
|
||||
std::transform(keyId.begin(), keyId.end(), keyId.begin(), ::tolower);
|
||||
for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it)
|
||||
{
|
||||
if (it->getCellRef ().mRefID == ptr.getCellRef().mKey)
|
||||
std::string refId = it->getCellRef().mRefID;
|
||||
std::transform(refId.begin(), refId.end(), refId.begin(), ::tolower);
|
||||
if (refId == keyId)
|
||||
{
|
||||
hasKey = true;
|
||||
keyName = MWWorld::Class::get(*it).getName(*it);
|
||||
|
|
|
@ -41,9 +41,8 @@ namespace MWClass
|
|||
void Ingredient::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -53,12 +53,11 @@ namespace MWClass
|
|||
|
||||
const std::string &model = ref->base->mModel;
|
||||
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, "meshes\\" + model);
|
||||
}
|
||||
if (!ref->base->mSound.empty()) {
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
|
||||
if (!ref->base->mSound.empty())
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->base->mSound, 1.0, 1.0, MWBase::SoundManager::Play_Loop);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Light::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -34,9 +34,8 @@ namespace MWClass
|
|||
void Lockpick::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -37,9 +37,8 @@ namespace MWClass
|
|||
void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/actionopen.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
#include "../mwworld/physicssystem.hpp"
|
||||
|
@ -89,15 +90,22 @@ namespace MWClass
|
|||
data->mCreatureStats.getAttribute(5).set (ref->base->mNpdt52.mEndurance);
|
||||
data->mCreatureStats.getAttribute(6).set (ref->base->mNpdt52.mPersonality);
|
||||
data->mCreatureStats.getAttribute(7).set (ref->base->mNpdt52.mLuck);
|
||||
data->mCreatureStats.getHealth().set (ref->base->mNpdt52.mHealth);
|
||||
data->mCreatureStats.getMagicka().set (ref->base->mNpdt52.mMana);
|
||||
data->mCreatureStats.getFatigue().set (ref->base->mNpdt52.mFatigue);
|
||||
data->mCreatureStats.setHealth (ref->base->mNpdt52.mHealth);
|
||||
data->mCreatureStats.setMagicka (ref->base->mNpdt52.mMana);
|
||||
data->mCreatureStats.setFatigue (ref->base->mNpdt52.mFatigue);
|
||||
|
||||
data->mCreatureStats.setLevel(ref->base->mNpdt52.mLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
/// \todo do something with mNpdt12 maybe:p
|
||||
for (int i=0; i<8; ++i)
|
||||
data->mCreatureStats.getAttribute (i).set (10);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
data->mCreatureStats.setDynamic (i, 10);
|
||||
|
||||
data->mCreatureStats.setLevel (1);
|
||||
}
|
||||
|
||||
data->mCreatureStats.setHello(ref->base->mAiData.mHello);
|
||||
|
@ -130,7 +138,7 @@ namespace MWClass
|
|||
|
||||
void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
physics.insertActorPhysics(ptr, getModel(ptr));
|
||||
physics.addActor(ptr);
|
||||
MWBase::Environment::get().getMechanicsManager()->addActor(ptr);
|
||||
}
|
||||
|
||||
|
@ -182,7 +190,10 @@ namespace MWClass
|
|||
boost::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const
|
||||
{
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead())
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionOpen(ptr));
|
||||
else
|
||||
return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
|
||||
}
|
||||
|
||||
MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
|
||||
|
@ -308,7 +319,15 @@ namespace MWClass
|
|||
|
||||
return vector;
|
||||
}
|
||||
|
||||
bool Npc::isEssential (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::NPC> *ref =
|
||||
ptr.get<ESM::NPC>();
|
||||
|
||||
return ref->base->mFlags & ESM::NPC::Essential;
|
||||
}
|
||||
|
||||
void Npc::registerSelf()
|
||||
{
|
||||
boost::shared_ptr<Class> instance (new Npc);
|
||||
|
|
|
@ -90,6 +90,9 @@ namespace MWClass
|
|||
|
||||
virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const;
|
||||
|
||||
virtual bool isEssential (const MWWorld::Ptr& ptr) const;
|
||||
///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable)
|
||||
|
||||
static void registerSelf();
|
||||
|
||||
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
|
||||
|
|
|
@ -34,9 +34,8 @@ namespace MWClass
|
|||
void Potion::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Potion::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -34,9 +34,8 @@ namespace MWClass
|
|||
void Probe::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Probe::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -32,9 +32,8 @@ namespace MWClass
|
|||
void Repair::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Repair::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -24,9 +24,8 @@ namespace MWClass
|
|||
void Static::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Static::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -34,9 +34,8 @@ namespace MWClass
|
|||
void Weapon::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const
|
||||
{
|
||||
const std::string model = getModel(ptr);
|
||||
if(!model.empty()) {
|
||||
physics.insertObjectPhysics(ptr, model);
|
||||
}
|
||||
if(!model.empty())
|
||||
physics.addObject(ptr);
|
||||
}
|
||||
|
||||
std::string Weapon::getModel(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -145,16 +145,17 @@ namespace
|
|||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
|
||||
//helper function
|
||||
std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos)
|
||||
{
|
||||
return toLower(str).find(toLower(substr),pos);
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
|
||||
|
||||
bool DialogueManager::functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice)
|
||||
{
|
||||
|
@ -779,6 +780,8 @@ namespace MWDialogue
|
|||
services = ref->base->mAiData.mServices;
|
||||
}
|
||||
|
||||
int windowServices = 0;
|
||||
|
||||
if (services & ESM::NPC::Weapon
|
||||
|| services & ESM::NPC::Armor
|
||||
|| services & ESM::NPC::Clothing
|
||||
|
@ -790,14 +793,24 @@ namespace MWDialogue
|
|||
|| services & ESM::NPC::Apparatus
|
||||
|| services & ESM::NPC::RepairItem
|
||||
|| services & ESM::NPC::Misc)
|
||||
win->setShowTrade(true);
|
||||
else
|
||||
win->setShowTrade(false);
|
||||
windowServices |= MWGui::DialogueWindow::Service_Trade;
|
||||
|
||||
if( !mActor.get<ESM::NPC>()->base->mTransport.empty())
|
||||
windowServices |= MWGui::DialogueWindow::Service_Travel;
|
||||
|
||||
if (services & ESM::NPC::Spells)
|
||||
win->setShowSpells(true);
|
||||
else
|
||||
win->setShowSpells(false);
|
||||
windowServices |= MWGui::DialogueWindow::Service_BuySpells;
|
||||
|
||||
if (services & ESM::NPC::Spellmaking)
|
||||
windowServices |= MWGui::DialogueWindow::Service_CreateSpells;
|
||||
|
||||
if (services & ESM::NPC::Training)
|
||||
windowServices |= MWGui::DialogueWindow::Service_Training;
|
||||
|
||||
if (services & ESM::NPC::Enchanting)
|
||||
windowServices |= MWGui::DialogueWindow::Service_Enchant;
|
||||
|
||||
win->setServices (windowServices);
|
||||
|
||||
// sort again, because the previous sort was case-sensitive
|
||||
keywordList.sort(stringCompareNoCase);
|
||||
|
|
|
@ -28,25 +28,25 @@ namespace MWGui
|
|||
{
|
||||
AlchemyWindow::AlchemyWindow(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_alchemy_window.layout", parWindowManager)
|
||||
, ContainerBase(0)
|
||||
, ContainerBase(0), mApparatus (4), mIngredients (4)
|
||||
{
|
||||
getWidget(mCreateButton, "CreateButton");
|
||||
getWidget(mCancelButton, "CancelButton");
|
||||
getWidget(mIngredient1, "Ingredient1");
|
||||
getWidget(mIngredient2, "Ingredient2");
|
||||
getWidget(mIngredient3, "Ingredient3");
|
||||
getWidget(mIngredient4, "Ingredient4");
|
||||
getWidget(mApparatus1, "Apparatus1");
|
||||
getWidget(mApparatus2, "Apparatus2");
|
||||
getWidget(mApparatus3, "Apparatus3");
|
||||
getWidget(mApparatus4, "Apparatus4");
|
||||
getWidget(mIngredients[0], "Ingredient1");
|
||||
getWidget(mIngredients[1], "Ingredient2");
|
||||
getWidget(mIngredients[2], "Ingredient3");
|
||||
getWidget(mIngredients[3], "Ingredient4");
|
||||
getWidget(mApparatus[0], "Apparatus1");
|
||||
getWidget(mApparatus[1], "Apparatus2");
|
||||
getWidget(mApparatus[2], "Apparatus3");
|
||||
getWidget(mApparatus[3], "Apparatus4");
|
||||
getWidget(mEffectsBox, "CreatedEffects");
|
||||
getWidget(mNameEdit, "NameEdit");
|
||||
|
||||
mIngredient1->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||
mIngredient2->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||
mIngredient3->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||
mIngredient4->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||
mIngredients[0]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||
mIngredients[1]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||
mIngredients[2]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||
mIngredients[3]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||
|
||||
mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked);
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked);
|
||||
|
@ -62,157 +62,52 @@ namespace MWGui
|
|||
|
||||
void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
mAlchemy.clear();
|
||||
|
||||
mWindowManager.removeGuiMode(GM_Alchemy);
|
||||
mWindowManager.removeGuiMode(GM_Inventory);
|
||||
}
|
||||
|
||||
void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
std::string name = mNameEdit->getCaption();
|
||||
boost::algorithm::trim(name);
|
||||
|
||||
MWMechanics::Alchemy::Result result = mAlchemy.create (mNameEdit->getCaption ());
|
||||
|
||||
if (result == MWMechanics::Alchemy::Result_NoName)
|
||||
{
|
||||
mWindowManager.messageBox("#{sNotifyMessage37}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
// check if mortar & pestle is available (always needed)
|
||||
/// \todo check albemic, calcinator, retort (sometimes needed)
|
||||
if (!mApparatus1->isUserString("ToolTipType"))
|
||||
if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle)
|
||||
{
|
||||
mWindowManager.messageBox("#{sNotifyMessage45}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure 2 or more ingredients were selected
|
||||
int numIngreds = 0;
|
||||
if (mIngredient1->isUserString("ToolTipType"))
|
||||
++numIngreds;
|
||||
if (mIngredient2->isUserString("ToolTipType"))
|
||||
++numIngreds;
|
||||
if (mIngredient3->isUserString("ToolTipType"))
|
||||
++numIngreds;
|
||||
if (mIngredient4->isUserString("ToolTipType"))
|
||||
++numIngreds;
|
||||
if (numIngreds < 2)
|
||||
if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients)
|
||||
{
|
||||
mWindowManager.messageBox("#{sNotifyMessage6a}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure a name was entered
|
||||
std::string name = mNameEdit->getCaption();
|
||||
boost::algorithm::trim(name);
|
||||
if (name == "")
|
||||
{
|
||||
mWindowManager.messageBox("#{sNotifyMessage37}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
// if there are no created effects, the potion will always fail (but the ingredients won't be destroyed)
|
||||
if (mEffects.empty())
|
||||
if (result == MWMechanics::Alchemy::Result_NoEffects)
|
||||
{
|
||||
mWindowManager.messageBox("#{sNotifyMessage8}", std::vector<std::string>());
|
||||
MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rand() % 2 == 0) /// \todo
|
||||
if (result == MWMechanics::Alchemy::Result_Success)
|
||||
{
|
||||
ESM::Potion newPotion;
|
||||
newPotion.mName = mNameEdit->getCaption();
|
||||
ESM::EffectList effects;
|
||||
for (unsigned int i=0; i<4; ++i)
|
||||
{
|
||||
if (mEffects.size() >= i+1)
|
||||
{
|
||||
ESM::ENAMstruct effect;
|
||||
effect.mEffectID = mEffects[i].mEffectID;
|
||||
effect.mArea = 0;
|
||||
effect.mRange = ESM::RT_Self;
|
||||
effect.mSkill = mEffects[i].mSkill;
|
||||
effect.mAttribute = mEffects[i].mAttribute;
|
||||
effect.mMagnMin = 1; /// \todo
|
||||
effect.mMagnMax = 10; /// \todo
|
||||
effect.mDuration = 60; /// \todo
|
||||
effects.mList.push_back(effect);
|
||||
}
|
||||
}
|
||||
|
||||
// UESP Wiki / Morrowind:Alchemy
|
||||
// "The weight of a potion is an average of the weight of the ingredients, rounded down."
|
||||
// note by scrawl: not rounding down here, I can't imagine a created potion to
|
||||
// have 0 weight when using ingredients with 0.1 weight respectively
|
||||
float weight = 0;
|
||||
if (mIngredient1->isUserString("ToolTipType"))
|
||||
weight += mIngredient1->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>()->base->mData.mWeight;
|
||||
if (mIngredient2->isUserString("ToolTipType"))
|
||||
weight += mIngredient2->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>()->base->mData.mWeight;
|
||||
if (mIngredient3->isUserString("ToolTipType"))
|
||||
weight += mIngredient3->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>()->base->mData.mWeight;
|
||||
if (mIngredient4->isUserString("ToolTipType"))
|
||||
weight += mIngredient4->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>()->base->mData.mWeight;
|
||||
newPotion.mData.mWeight = weight / float(numIngreds);
|
||||
|
||||
newPotion.mData.mValue = 100; /// \todo
|
||||
newPotion.mEffects = effects;
|
||||
// pick a random mesh and icon
|
||||
std::vector<std::string> names;
|
||||
/// \todo is the mesh/icon dependent on alchemy skill?
|
||||
names.push_back("standard");
|
||||
names.push_back("bargain");
|
||||
names.push_back("cheap");
|
||||
names.push_back("fresh");
|
||||
names.push_back("exclusive");
|
||||
names.push_back("quality");
|
||||
int random = rand() % names.size();
|
||||
newPotion.mModel = "m\\misc_potion_" + names[random ] + "_01.nif";
|
||||
newPotion.mIcon = "m\\tx_potion_" + names[random ] + "_01.dds";
|
||||
|
||||
// check if a similiar potion record exists already
|
||||
bool found = false;
|
||||
std::string objectId;
|
||||
typedef std::map<std::string, ESM::Potion> PotionMap;
|
||||
PotionMap potions = MWBase::Environment::get().getWorld()->getStore().potions.list;
|
||||
for (PotionMap::const_iterator it = potions.begin(); it != potions.end(); ++it)
|
||||
{
|
||||
if (found) break;
|
||||
|
||||
if (it->second.mData.mValue == newPotion.mData.mValue
|
||||
&& it->second.mData.mWeight == newPotion.mData.mWeight
|
||||
&& it->second.mName == newPotion.mName
|
||||
&& it->second.mEffects.mList.size() == newPotion.mEffects.mList.size())
|
||||
{
|
||||
// check effects
|
||||
for (unsigned int i=0; i < it->second.mEffects.mList.size(); ++i)
|
||||
{
|
||||
const ESM::ENAMstruct& a = it->second.mEffects.mList[i];
|
||||
const ESM::ENAMstruct& b = newPotion.mEffects.mList[i];
|
||||
if (a.mEffectID == b.mEffectID
|
||||
&& a.mArea == b.mArea
|
||||
&& a.mRange == b.mRange
|
||||
&& a.mSkill == b.mSkill
|
||||
&& a.mAttribute == b.mAttribute
|
||||
&& a.mMagnMin == b.mMagnMin
|
||||
&& a.mMagnMax == b.mMagnMax
|
||||
&& a.mDuration == b.mDuration)
|
||||
{
|
||||
found = true;
|
||||
objectId = it->first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
std::pair<std::string, const ESM::Potion*> result = MWBase::Environment::get().getWorld()->createRecord(newPotion);
|
||||
objectId = result.first;
|
||||
}
|
||||
|
||||
// create a reference and add it to player inventory
|
||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), objectId);
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
|
||||
ref.getPtr().getRefData().setCount(1);
|
||||
store.add(ref.getPtr());
|
||||
|
||||
mWindowManager.messageBox("#{sPotionSuccess}", std::vector<std::string>());
|
||||
MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f);
|
||||
}
|
||||
else
|
||||
else if (result == MWMechanics::Alchemy::Result_RandomFailure)
|
||||
{
|
||||
// potion failed
|
||||
mWindowManager.messageBox("#{sNotifyMessage8}", std::vector<std::string>());
|
||||
|
@ -220,155 +115,55 @@ namespace MWGui
|
|||
}
|
||||
|
||||
// reduce count of the ingredients
|
||||
if (mIngredient1->isUserString("ToolTipType"))
|
||||
{
|
||||
MWWorld::Ptr ingred = *mIngredient1->getUserData<MWWorld::Ptr>();
|
||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
||||
if (ingred.getRefData().getCount() == 0)
|
||||
removeIngredient(mIngredient1);
|
||||
}
|
||||
if (mIngredient2->isUserString("ToolTipType"))
|
||||
{
|
||||
MWWorld::Ptr ingred = *mIngredient2->getUserData<MWWorld::Ptr>();
|
||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
||||
if (ingred.getRefData().getCount() == 0)
|
||||
removeIngredient(mIngredient2);
|
||||
}
|
||||
if (mIngredient3->isUserString("ToolTipType"))
|
||||
{
|
||||
MWWorld::Ptr ingred = *mIngredient3->getUserData<MWWorld::Ptr>();
|
||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
||||
if (ingred.getRefData().getCount() == 0)
|
||||
removeIngredient(mIngredient3);
|
||||
}
|
||||
if (mIngredient4->isUserString("ToolTipType"))
|
||||
{
|
||||
MWWorld::Ptr ingred = *mIngredient4->getUserData<MWWorld::Ptr>();
|
||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
||||
if (ingred.getRefData().getCount() == 0)
|
||||
removeIngredient(mIngredient4);
|
||||
for (int i=0; i<4; ++i)
|
||||
if (mIngredients[i]->isUserString("ToolTipType"))
|
||||
{
|
||||
MWWorld::Ptr ingred = *mIngredients[i]->getUserData<MWWorld::Ptr>();
|
||||
ingred.getRefData().setCount(ingred.getRefData().getCount()-1);
|
||||
if (ingred.getRefData().getCount() == 0)
|
||||
removeIngredient(mIngredients[i]);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void AlchemyWindow::open()
|
||||
{
|
||||
openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
|
||||
setFilter(ContainerBase::Filter_Ingredients);
|
||||
openContainer (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); // this sets mPtr
|
||||
setFilter (ContainerBase::Filter_Ingredients);
|
||||
|
||||
// pick the best available apparatus
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
|
||||
mNameEdit->setCaption("");
|
||||
|
||||
MWWorld::Ptr bestAlbemic;
|
||||
MWWorld::Ptr bestMortarPestle;
|
||||
MWWorld::Ptr bestCalcinator;
|
||||
MWWorld::Ptr bestRetort;
|
||||
mAlchemy.setAlchemist (mPtr);
|
||||
|
||||
for (MWWorld::ContainerStoreIterator it(store.begin(MWWorld::ContainerStore::Type_Apparatus));
|
||||
it != store.end(); ++it)
|
||||
int index = 0;
|
||||
|
||||
for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy.beginTools());
|
||||
iter!=mAlchemy.endTools() && index<static_cast<int> (mApparatus.size()); ++iter, ++index)
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Apparatus>* ref = it->get<ESM::Apparatus>();
|
||||
if (ref->base->mData.mType == ESM::Apparatus::Albemic
|
||||
&& (bestAlbemic.isEmpty() || ref->base->mData.mQuality > bestAlbemic.get<ESM::Apparatus>()->base->mData.mQuality))
|
||||
bestAlbemic = *it;
|
||||
else if (ref->base->mData.mType == ESM::Apparatus::MortarPestle
|
||||
&& (bestMortarPestle.isEmpty() || ref->base->mData.mQuality > bestMortarPestle.get<ESM::Apparatus>()->base->mData.mQuality))
|
||||
bestMortarPestle = *it;
|
||||
else if (ref->base->mData.mType == ESM::Apparatus::Calcinator
|
||||
&& (bestCalcinator.isEmpty() || ref->base->mData.mQuality > bestCalcinator.get<ESM::Apparatus>()->base->mData.mQuality))
|
||||
bestCalcinator = *it;
|
||||
else if (ref->base->mData.mType == ESM::Apparatus::Retort
|
||||
&& (bestRetort.isEmpty() || ref->base->mData.mQuality > bestRetort.get<ESM::Apparatus>()->base->mData.mQuality))
|
||||
bestRetort = *it;
|
||||
if (!iter->isEmpty())
|
||||
{
|
||||
mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr");
|
||||
mApparatus.at (index)->setUserData (*iter);
|
||||
mApparatus.at (index)->setImageTexture (getIconPath (*iter));
|
||||
}
|
||||
}
|
||||
|
||||
if (!bestMortarPestle.isEmpty())
|
||||
{
|
||||
mApparatus1->setUserString("ToolTipType", "ItemPtr");
|
||||
mApparatus1->setUserData(bestMortarPestle);
|
||||
mApparatus1->setImageTexture(getIconPath(bestMortarPestle));
|
||||
}
|
||||
if (!bestAlbemic.isEmpty())
|
||||
{
|
||||
mApparatus2->setUserString("ToolTipType", "ItemPtr");
|
||||
mApparatus2->setUserData(bestAlbemic);
|
||||
mApparatus2->setImageTexture(getIconPath(bestAlbemic));
|
||||
}
|
||||
if (!bestCalcinator.isEmpty())
|
||||
{
|
||||
mApparatus3->setUserString("ToolTipType", "ItemPtr");
|
||||
mApparatus3->setUserData(bestCalcinator);
|
||||
mApparatus3->setImageTexture(getIconPath(bestCalcinator));
|
||||
}
|
||||
if (!bestRetort.isEmpty())
|
||||
{
|
||||
mApparatus4->setUserString("ToolTipType", "ItemPtr");
|
||||
mApparatus4->setUserData(bestRetort);
|
||||
mApparatus4->setImageTexture(getIconPath(bestRetort));
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender)
|
||||
{
|
||||
removeIngredient(_sender);
|
||||
drawItems();
|
||||
update();
|
||||
}
|
||||
|
||||
void AlchemyWindow::onSelectedItemImpl(MWWorld::Ptr item)
|
||||
{
|
||||
MyGUI::ImageBox* add = NULL;
|
||||
int res = mAlchemy.addIngredient(item);
|
||||
|
||||
// don't allow to add an ingredient that is already added
|
||||
// (which could happen if two similiar ingredients don't stack because of script / owner)
|
||||
bool alreadyAdded = false;
|
||||
std::string name = MWWorld::Class::get(item).getName(item);
|
||||
if (mIngredient1->isUserString("ToolTipType"))
|
||||
if (res != -1)
|
||||
{
|
||||
MWWorld::Ptr item2 = *mIngredient1->getUserData<MWWorld::Ptr>();
|
||||
std::string name2 = MWWorld::Class::get(item2).getName(item2);
|
||||
if (name == name2)
|
||||
alreadyAdded = true;
|
||||
}
|
||||
if (mIngredient2->isUserString("ToolTipType"))
|
||||
{
|
||||
MWWorld::Ptr item2 = *mIngredient2->getUserData<MWWorld::Ptr>();
|
||||
std::string name2 = MWWorld::Class::get(item2).getName(item2);
|
||||
if (name == name2)
|
||||
alreadyAdded = true;
|
||||
}
|
||||
if (mIngredient3->isUserString("ToolTipType"))
|
||||
{
|
||||
MWWorld::Ptr item2 = *mIngredient3->getUserData<MWWorld::Ptr>();
|
||||
std::string name2 = MWWorld::Class::get(item2).getName(item2);
|
||||
if (name == name2)
|
||||
alreadyAdded = true;
|
||||
}
|
||||
if (mIngredient4->isUserString("ToolTipType"))
|
||||
{
|
||||
MWWorld::Ptr item2 = *mIngredient4->getUserData<MWWorld::Ptr>();
|
||||
std::string name2 = MWWorld::Class::get(item2).getName(item2);
|
||||
if (name == name2)
|
||||
alreadyAdded = true;
|
||||
}
|
||||
if (alreadyAdded)
|
||||
return;
|
||||
|
||||
if (!mIngredient1->isUserString("ToolTipType"))
|
||||
add = mIngredient1;
|
||||
if (add == NULL && !mIngredient2->isUserString("ToolTipType"))
|
||||
add = mIngredient2;
|
||||
if (add == NULL && !mIngredient3->isUserString("ToolTipType"))
|
||||
add = mIngredient3;
|
||||
if (add == NULL && !mIngredient4->isUserString("ToolTipType"))
|
||||
add = mIngredient4;
|
||||
|
||||
if (add != NULL)
|
||||
{
|
||||
add->setUserString("ToolTipType", "ItemPtr");
|
||||
add->setUserData(item);
|
||||
add->setImageTexture(getIconPath(item));
|
||||
drawItems();
|
||||
update();
|
||||
|
||||
std::string sound = MWWorld::Class::get(item).getUpSoundId(item);
|
||||
|
@ -380,54 +175,40 @@ namespace MWGui
|
|||
{
|
||||
std::vector<MWWorld::Ptr> ignore;
|
||||
// don't show ingredients that are currently selected in the "available ingredients" box.
|
||||
if (mIngredient1->isUserString("ToolTipType"))
|
||||
ignore.push_back(*mIngredient1->getUserData<MWWorld::Ptr>());
|
||||
if (mIngredient2->isUserString("ToolTipType"))
|
||||
ignore.push_back(*mIngredient2->getUserData<MWWorld::Ptr>());
|
||||
if (mIngredient3->isUserString("ToolTipType"))
|
||||
ignore.push_back(*mIngredient3->getUserData<MWWorld::Ptr>());
|
||||
if (mIngredient4->isUserString("ToolTipType"))
|
||||
ignore.push_back(*mIngredient4->getUserData<MWWorld::Ptr>());
|
||||
for (int i=0; i<4; ++i)
|
||||
if (mIngredients[i]->isUserString("ToolTipType"))
|
||||
ignore.push_back(*mIngredients[i]->getUserData<MWWorld::Ptr>());
|
||||
|
||||
return ignore;
|
||||
}
|
||||
|
||||
void AlchemyWindow::update()
|
||||
{
|
||||
Widgets::SpellEffectList effects;
|
||||
|
||||
MWMechanics::Alchemy::TIngredientsIterator it = mAlchemy.beginIngredients ();
|
||||
for (int i=0; i<4; ++i)
|
||||
{
|
||||
MyGUI::ImageBox* ingredient;
|
||||
if (i==0)
|
||||
ingredient = mIngredient1;
|
||||
else if (i==1)
|
||||
ingredient = mIngredient2;
|
||||
else if (i==2)
|
||||
ingredient = mIngredient3;
|
||||
else if (i==3)
|
||||
ingredient = mIngredient4;
|
||||
MyGUI::ImageBox* ingredient = mIngredients[i];
|
||||
|
||||
if (!ingredient->isUserString("ToolTipType"))
|
||||
continue;
|
||||
|
||||
// add the effects of this ingredient to list of effects
|
||||
MWWorld::LiveCellRef<ESM::Ingredient>* ref = ingredient->getUserData<MWWorld::Ptr>()->get<ESM::Ingredient>();
|
||||
for (int i=0; i<4; ++i)
|
||||
MWWorld::Ptr item;
|
||||
if (it != mAlchemy.endIngredients ())
|
||||
{
|
||||
if (ref->base->mData.mEffectID[i] < 0)
|
||||
continue;
|
||||
MWGui::Widgets::SpellEffectParams params;
|
||||
params.mEffectID = ref->base->mData.mEffectID[i];
|
||||
params.mAttribute = ref->base->mData.mAttributes[i];
|
||||
params.mSkill = ref->base->mData.mSkills[i];
|
||||
effects.push_back(params);
|
||||
item = *it;
|
||||
++it;
|
||||
}
|
||||
|
||||
// update ingredient count labels
|
||||
if (ingredient->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0));
|
||||
|
||||
ingredient->setImageTexture("");
|
||||
ingredient->clearUserStrings ();
|
||||
|
||||
if (item.isEmpty ())
|
||||
continue;
|
||||
|
||||
ingredient->setUserString("ToolTipType", "ItemPtr");
|
||||
ingredient->setUserData(item);
|
||||
ingredient->setImageTexture(getIconPath(item));
|
||||
|
||||
MyGUI::TextBox* text = ingredient->createWidget<MyGUI::TextBox>("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label"));
|
||||
text->setTextAlign(MyGUI::Align::Right);
|
||||
text->setNeedMouseFocus(false);
|
||||
|
@ -436,49 +217,15 @@ namespace MWGui
|
|||
text->setCaption(getCountString(ingredient->getUserData<MWWorld::Ptr>()->getRefData().getCount()));
|
||||
}
|
||||
|
||||
// now remove effects that are only present once
|
||||
Widgets::SpellEffectList::iterator it = effects.begin();
|
||||
while (it != effects.end())
|
||||
{
|
||||
Widgets::SpellEffectList::iterator next = it;
|
||||
++next;
|
||||
bool found = false;
|
||||
for (; next != effects.end(); ++next)
|
||||
{
|
||||
if (*next == *it)
|
||||
found = true;
|
||||
}
|
||||
drawItems();
|
||||
|
||||
if (!found)
|
||||
it = effects.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
// now remove duplicates, and don't allow more than 4 effects
|
||||
Widgets::SpellEffectList old = effects;
|
||||
effects.clear();
|
||||
int i=0;
|
||||
for (Widgets::SpellEffectList::iterator it = old.begin();
|
||||
it != old.end(); ++it)
|
||||
std::vector<ESM::ENAMstruct> effects;
|
||||
ESM::EffectList list;
|
||||
list.mList = effects;
|
||||
for (MWMechanics::Alchemy::TEffectsIterator it = mAlchemy.beginEffects (); it != mAlchemy.endEffects (); ++it)
|
||||
{
|
||||
bool found = false;
|
||||
for (Widgets::SpellEffectList::iterator it2 = effects.begin();
|
||||
it2 != effects.end(); ++it2)
|
||||
{
|
||||
// MW considers all "foritfy attribute" effects as the same effect. See the
|
||||
// "Can't create multi-state boost potions" discussion on http://www.uesp.net/wiki/Morrowind_talk:Alchemy
|
||||
// thus, we are only checking effectID here and not attribute or skill
|
||||
if (it2->mEffectID == it->mEffectID)
|
||||
found = true;
|
||||
}
|
||||
if (!found && i<4)
|
||||
{
|
||||
++i;
|
||||
effects.push_back(*it);
|
||||
}
|
||||
list.mList.push_back(*it);
|
||||
}
|
||||
mEffects = effects;
|
||||
|
||||
while (mEffectsBox->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mEffectsBox->getChildAt(0));
|
||||
|
@ -487,7 +234,9 @@ namespace MWGui
|
|||
Widgets::MWEffectListPtr effectsWidget = mEffectsBox->createWidget<Widgets::MWEffectList>
|
||||
("MW_StatName", coord, MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
effectsWidget->setWindowManager(&mWindowManager);
|
||||
effectsWidget->setEffectList(effects);
|
||||
|
||||
Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list);
|
||||
effectsWidget->setEffectList(_list);
|
||||
|
||||
std::vector<MyGUI::WidgetPtr> effectItems;
|
||||
effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0);
|
||||
|
@ -496,9 +245,10 @@ namespace MWGui
|
|||
|
||||
void AlchemyWindow::removeIngredient(MyGUI::Widget* ingredient)
|
||||
{
|
||||
ingredient->clearUserStrings();
|
||||
static_cast<MyGUI::ImageBox*>(ingredient)->setImageTexture("");
|
||||
if (ingredient->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0));
|
||||
for (int i=0; i<4; ++i)
|
||||
if (mIngredients[i] == ingredient)
|
||||
mAlchemy.removeIngredient (i);
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#ifndef MWGUI_ALCHEMY_H
|
||||
#define MWGUI_ALCHEMY_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../mwmechanics/alchemy.hpp"
|
||||
|
||||
#include "window_base.hpp"
|
||||
#include "container.hpp"
|
||||
#include "widgets.hpp"
|
||||
|
@ -18,22 +22,10 @@ namespace MWGui
|
|||
MyGUI::Button* mCreateButton;
|
||||
MyGUI::Button* mCancelButton;
|
||||
|
||||
MyGUI::ImageBox* mIngredient1;
|
||||
MyGUI::ImageBox* mIngredient2;
|
||||
MyGUI::ImageBox* mIngredient3;
|
||||
MyGUI::ImageBox* mIngredient4;
|
||||
|
||||
MyGUI::ImageBox* mApparatus1;
|
||||
MyGUI::ImageBox* mApparatus2;
|
||||
MyGUI::ImageBox* mApparatus3;
|
||||
MyGUI::ImageBox* mApparatus4;
|
||||
|
||||
MyGUI::Widget* mEffectsBox;
|
||||
|
||||
MyGUI::EditBox* mNameEdit;
|
||||
|
||||
Widgets::SpellEffectList mEffects; // effects of created potion
|
||||
|
||||
void onCancelButtonClicked(MyGUI::Widget* _sender);
|
||||
void onCreateButtonClicked(MyGUI::Widget* _sender);
|
||||
void onIngredientSelected(MyGUI::Widget* _sender);
|
||||
|
@ -46,6 +38,13 @@ namespace MWGui
|
|||
virtual void onReferenceUnavailable() { ; }
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
|
||||
MWMechanics::Alchemy mAlchemy;
|
||||
|
||||
std::vector<MyGUI::ImageBox *> mApparatus;
|
||||
std::vector<MyGUI::ImageBox *> mIngredients;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,16 @@
|
|||
using namespace MWGui;
|
||||
using namespace Widgets;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool sortBirthSigns(const std::pair<std::string, const ESM::BirthSign*>& left, const std::pair<std::string, const ESM::BirthSign*>& right)
|
||||
{
|
||||
return left.second->mName.compare (right.second->mName) < 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_chargen_birth.layout", parWindowManager)
|
||||
{
|
||||
|
@ -38,6 +48,7 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager)
|
|||
getWidget(okButton, "OKButton");
|
||||
okButton->setCaption(mWindowManager.getGameSettingString("sOK", ""));
|
||||
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked);
|
||||
okButton->setEnabled(false);
|
||||
|
||||
updateBirths();
|
||||
updateSpells();
|
||||
|
@ -72,6 +83,9 @@ void BirthDialog::setBirthId(const std::string &birthId)
|
|||
if (boost::iequals(*mBirthList->getItemDataAt<std::string>(i), birthId))
|
||||
{
|
||||
mBirthList->setIndexSelected(i);
|
||||
MyGUI::ButtonPtr okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
okButton->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +97,8 @@ void BirthDialog::setBirthId(const std::string &birthId)
|
|||
|
||||
void BirthDialog::onOkClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
if(mBirthList->getIndexSelected() == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
|
@ -96,6 +112,10 @@ void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index)
|
|||
if (_index == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
|
||||
MyGUI::ButtonPtr okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
okButton->setEnabled(true);
|
||||
|
||||
const std::string *birthId = mBirthList->getItemDataAt<std::string>(_index);
|
||||
if (boost::iequals(mCurrentBirthId, *birthId))
|
||||
return;
|
||||
|
@ -115,11 +135,21 @@ void BirthDialog::updateBirths()
|
|||
ESMS::RecListT<ESM::BirthSign>::MapType::const_iterator it = store.birthSigns.list.begin();
|
||||
ESMS::RecListT<ESM::BirthSign>::MapType::const_iterator end = store.birthSigns.list.end();
|
||||
int index = 0;
|
||||
for (; it != end; ++it)
|
||||
|
||||
// sort by name
|
||||
std::vector < std::pair<std::string, const ESM::BirthSign*> > birthSigns;
|
||||
for (; it!=end; ++it)
|
||||
{
|
||||
const ESM::BirthSign &birth = it->second;
|
||||
mBirthList->addItem(birth.mName, it->first);
|
||||
if (boost::iequals(it->first, mCurrentBirthId))
|
||||
std::string id = it->first;
|
||||
const ESM::BirthSign* sign = &it->second;
|
||||
birthSigns.push_back(std::make_pair(id, sign));
|
||||
}
|
||||
std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns);
|
||||
|
||||
for (std::vector < std::pair<std::string, const ESM::BirthSign*> >::const_iterator it2 = birthSigns.begin(); it2 != birthSigns.end(); ++it2)
|
||||
{
|
||||
mBirthList->addItem(it2->second->mName, it2->first);
|
||||
if (boost::iequals(it2->first, mCurrentBirthId))
|
||||
mBirthList->setIndexSelected(index);
|
||||
++index;
|
||||
}
|
||||
|
|
|
@ -232,6 +232,7 @@ void CharacterCreation::spawnDialog(const char id)
|
|||
mBirthSignDialog = 0;
|
||||
mBirthSignDialog = new BirthDialog(*mWM);
|
||||
mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen);
|
||||
mBirthSignDialog->setBirthId(mPlayerBirthSignId);
|
||||
mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone);
|
||||
mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack);
|
||||
mBirthSignDialog->setVisible(true);
|
||||
|
|
|
@ -104,6 +104,7 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager)
|
|||
MyGUI::ButtonPtr okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked);
|
||||
okButton->setEnabled(false);
|
||||
|
||||
updateClasses();
|
||||
updateStats();
|
||||
|
@ -137,6 +138,9 @@ void PickClassDialog::setClassId(const std::string &classId)
|
|||
if (boost::iequals(*mClassList->getItemDataAt<std::string>(i), classId))
|
||||
{
|
||||
mClassList->setIndexSelected(i);
|
||||
MyGUI::ButtonPtr okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
okButton->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -148,6 +152,8 @@ void PickClassDialog::setClassId(const std::string &classId)
|
|||
|
||||
void PickClassDialog::onOkClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
if(mClassList->getIndexSelected() == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
|
@ -161,6 +167,10 @@ void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index)
|
|||
if (_index == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
|
||||
MyGUI::ButtonPtr okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
okButton->setEnabled(true);
|
||||
|
||||
const std::string *classId = mClassList->getItemDataAt<std::string>(_index);
|
||||
if (boost::iequals(mCurrentClassId, *classId))
|
||||
return;
|
||||
|
@ -565,7 +575,7 @@ void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender)
|
|||
{
|
||||
delete mAttribDialog;
|
||||
mAttribDialog = new SelectAttributeDialog(mWindowManager);
|
||||
mAttribDialog->setAffectedWidget(_sender);
|
||||
mAffectedAttribute = _sender;
|
||||
mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
|
||||
mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected);
|
||||
mAttribDialog->setVisible(true);
|
||||
|
@ -574,18 +584,17 @@ void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender)
|
|||
void CreateClassDialog::onAttributeSelected()
|
||||
{
|
||||
ESM::Attribute::AttributeID id = mAttribDialog->getAttributeId();
|
||||
Widgets::MWAttributePtr attribute = mAttribDialog->getAffectedWidget();
|
||||
if (attribute == mFavoriteAttribute0)
|
||||
if (mAffectedAttribute == mFavoriteAttribute0)
|
||||
{
|
||||
if (mFavoriteAttribute1->getAttributeId() == id)
|
||||
mFavoriteAttribute1->setAttributeId(mFavoriteAttribute0->getAttributeId());
|
||||
}
|
||||
else if (attribute == mFavoriteAttribute1)
|
||||
else if (mAffectedAttribute == mFavoriteAttribute1)
|
||||
{
|
||||
if (mFavoriteAttribute0->getAttributeId() == id)
|
||||
mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId());
|
||||
}
|
||||
attribute->setAttributeId(id);
|
||||
mAffectedAttribute->setAttributeId(id);
|
||||
mWindowManager.removeDialog(mAttribDialog);
|
||||
mAttribDialog = 0;
|
||||
|
||||
|
@ -596,7 +605,7 @@ void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender)
|
|||
{
|
||||
delete mSkillDialog;
|
||||
mSkillDialog = new SelectSkillDialog(mWindowManager);
|
||||
mSkillDialog->setAffectedWidget(_sender);
|
||||
mAffectedSkill = _sender;
|
||||
mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
|
||||
mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected);
|
||||
mSkillDialog->setVisible(true);
|
||||
|
@ -605,22 +614,21 @@ void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender)
|
|||
void CreateClassDialog::onSkillSelected()
|
||||
{
|
||||
ESM::Skill::SkillEnum id = mSkillDialog->getSkillId();
|
||||
Widgets::MWSkillPtr skill = mSkillDialog->getAffectedWidget();
|
||||
|
||||
// Avoid duplicate skills by swapping any skill field that matches the selected one
|
||||
std::vector<Widgets::MWSkillPtr>::const_iterator end = mSkills.end();
|
||||
for (std::vector<Widgets::MWSkillPtr>::const_iterator it = mSkills.begin(); it != end; ++it)
|
||||
{
|
||||
if (*it == skill)
|
||||
if (*it == mAffectedSkill)
|
||||
continue;
|
||||
if ((*it)->getSkillId() == id)
|
||||
{
|
||||
(*it)->setSkillId(skill->getSkillId());
|
||||
(*it)->setSkillId(mAffectedSkill->getSkillId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
skill->setSkillId(mSkillDialog->getSkillId());
|
||||
mAffectedSkill->setSkillId(mSkillDialog->getSkillId());
|
||||
mWindowManager.removeDialog(mSkillDialog);
|
||||
mSkillDialog = 0;
|
||||
update();
|
||||
|
@ -643,6 +651,8 @@ void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow)
|
|||
|
||||
void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
if(getName().size() <= 0)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -167,8 +167,6 @@ namespace MWGui
|
|||
~SelectAttributeDialog();
|
||||
|
||||
ESM::Attribute::AttributeID getAttributeId() const { return mAttributeId; }
|
||||
Widgets::MWAttributePtr getAffectedWidget() const { return mAffectedWidget; }
|
||||
void setAffectedWidget(Widgets::MWAttributePtr widget) { mAffectedWidget = widget; }
|
||||
|
||||
// Events
|
||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||
|
@ -188,8 +186,6 @@ namespace MWGui
|
|||
void onCancelClicked(MyGUI::Widget* _sender);
|
||||
|
||||
private:
|
||||
Widgets::MWAttributePtr mAffectedWidget;
|
||||
|
||||
ESM::Attribute::AttributeID mAttributeId;
|
||||
};
|
||||
|
||||
|
@ -200,8 +196,6 @@ namespace MWGui
|
|||
~SelectSkillDialog();
|
||||
|
||||
ESM::Skill::SkillEnum getSkillId() const { return mSkillId; }
|
||||
Widgets::MWSkillPtr getAffectedWidget() const { return mAffectedWidget; }
|
||||
void setAffectedWidget(Widgets::MWSkillPtr widget) { mAffectedWidget = widget; }
|
||||
|
||||
// Events
|
||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||
|
@ -224,7 +218,6 @@ namespace MWGui
|
|||
Widgets::MWSkillPtr mCombatSkill[9];
|
||||
Widgets::MWSkillPtr mMagicSkill[9];
|
||||
Widgets::MWSkillPtr mStealthSkill[9];
|
||||
Widgets::MWSkillPtr mAffectedWidget;
|
||||
|
||||
ESM::Skill::SkillEnum mSkillId;
|
||||
};
|
||||
|
@ -301,6 +294,9 @@ namespace MWGui
|
|||
DescriptionDialog *mDescDialog;
|
||||
|
||||
ESM::Class::Specialization mSpecializationId;
|
||||
|
||||
Widgets::MWAttributePtr mAffectedAttribute;
|
||||
Widgets::MWSkillPtr mAffectedSkill;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "tradewindow.hpp"
|
||||
#include "spellbuyingwindow.hpp"
|
||||
#include "inventorywindow.hpp"
|
||||
#include "travelwindow.hpp"
|
||||
|
||||
using namespace MWGui;
|
||||
using namespace Widgets;
|
||||
|
@ -27,6 +28,8 @@ using namespace Widgets;
|
|||
*Copied from the internet.
|
||||
*/
|
||||
|
||||
namespace {
|
||||
|
||||
std::string lower_string(const std::string& str)
|
||||
{
|
||||
std::string lowerCase;
|
||||
|
@ -42,12 +45,13 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su
|
|||
return lower_string(str).find(lower_string(substr),pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_dialogue_window.layout", parWindowManager)
|
||||
, mEnabled(true)
|
||||
, mShowTrade(false)
|
||||
, mShowSpells(false)
|
||||
, mServices(0)
|
||||
{
|
||||
// Centre dialog
|
||||
center();
|
||||
|
@ -134,7 +138,26 @@ void DialogueWindow::onSelectTopic(std::string topic)
|
|||
mWindowManager.pushGuiMode(GM_SpellBuying);
|
||||
mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr);
|
||||
}
|
||||
|
||||
else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sTravel")->getString())
|
||||
{
|
||||
mWindowManager.pushGuiMode(GM_Travel);
|
||||
mWindowManager.getTravelWindow()->startTravel(mPtr);
|
||||
}
|
||||
else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpellMakingMenuTitle")->getString())
|
||||
{
|
||||
mWindowManager.pushGuiMode(GM_SpellCreation);
|
||||
mWindowManager.startSpellMaking (mPtr);
|
||||
}
|
||||
else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sEnchanting")->getString())
|
||||
{
|
||||
mWindowManager.pushGuiMode(GM_Enchanting);
|
||||
mWindowManager.startEnchanting (mPtr);
|
||||
}
|
||||
else if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sServiceTrainingTitle")->getString())
|
||||
{
|
||||
mWindowManager.pushGuiMode(GM_Training);
|
||||
mWindowManager.startTraining (mPtr);
|
||||
}
|
||||
else
|
||||
MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic));
|
||||
}
|
||||
|
@ -147,7 +170,7 @@ void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName)
|
|||
setTitle(npcName);
|
||||
|
||||
mTopicsList->clear();
|
||||
mHistory->eraseText(0,mHistory->getTextLength());
|
||||
mHistory->setCaption("");
|
||||
updateOptions();
|
||||
}
|
||||
|
||||
|
@ -155,14 +178,26 @@ void DialogueWindow::setKeywords(std::list<std::string> keyWords)
|
|||
{
|
||||
mTopicsList->clear();
|
||||
|
||||
bool anyService = mShowTrade||mShowSpells;
|
||||
bool anyService = mServices > 0;
|
||||
|
||||
if (mShowTrade)
|
||||
if (mServices & Service_Trade)
|
||||
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sBarter")->getString());
|
||||
|
||||
if (mShowSpells)
|
||||
if (mServices & Service_BuySpells)
|
||||
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpells")->getString());
|
||||
|
||||
if (mServices & Service_Travel)
|
||||
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sTravel")->getString());
|
||||
|
||||
if (mServices & Service_CreateSpells)
|
||||
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sSpellmakingMenuTitle")->getString());
|
||||
|
||||
// if (mServices & Service_Enchant)
|
||||
// mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sEnchanting")->getString());
|
||||
|
||||
if (mServices & Service_Training)
|
||||
mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.find("sServiceTrainingTitle")->getString());
|
||||
|
||||
if (anyService)
|
||||
mTopicsList->addSeparator();
|
||||
|
||||
|
|
|
@ -48,10 +48,18 @@ namespace MWGui
|
|||
void askQuestion(std::string question);
|
||||
void goodbye();
|
||||
|
||||
// various service button visibilities, depending if the npc/creature talked to has these services
|
||||
// make sure to call these before setKeywords()
|
||||
void setShowTrade(bool show) { mShowTrade = show; }
|
||||
void setShowSpells(bool show) { mShowSpells = show; }
|
||||
void setServices(int services) { mServices = services; }
|
||||
|
||||
enum Services
|
||||
{
|
||||
Service_Trade = 0x01,
|
||||
Service_BuySpells = 0x02,
|
||||
Service_CreateSpells = 0x04,
|
||||
Service_Enchant = 0x08,
|
||||
Service_Training = 0x10,
|
||||
Service_Travel = 0x20
|
||||
};
|
||||
|
||||
protected:
|
||||
void onSelectTopic(std::string topic);
|
||||
|
@ -69,9 +77,7 @@ namespace MWGui
|
|||
*/
|
||||
std::string parseText(std::string text);
|
||||
|
||||
// various service button visibilities, depending if the npc/creature talked to has these services
|
||||
bool mShowTrade;
|
||||
bool mShowSpells;
|
||||
int mServices;
|
||||
|
||||
bool mEnabled;
|
||||
|
||||
|
|
43
apps/openmw/mwgui/enchantingdialog.cpp
Normal file
43
apps/openmw/mwgui/enchantingdialog.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "enchantingdialog.hpp"
|
||||
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
|
||||
EnchantingDialog::EnchantingDialog(MWBase::WindowManager &parWindowManager)
|
||||
: WindowBase("openmw_enchanting_dialog.layout", parWindowManager)
|
||||
, EffectEditorBase(parWindowManager)
|
||||
{
|
||||
getWidget(mCancelButton, "CancelButton");
|
||||
getWidget(mAvailableEffectsList, "AvailableEffects");
|
||||
getWidget(mUsedEffectsView, "UsedEffects");
|
||||
|
||||
setWidgets(mAvailableEffectsList, mUsedEffectsView);
|
||||
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onCancelButtonClicked);
|
||||
}
|
||||
|
||||
void EnchantingDialog::open()
|
||||
{
|
||||
center();
|
||||
}
|
||||
|
||||
void EnchantingDialog::startEnchanting (MWWorld::Ptr actor)
|
||||
{
|
||||
mPtr = actor;
|
||||
|
||||
startEditing ();
|
||||
}
|
||||
|
||||
void EnchantingDialog::onReferenceUnavailable ()
|
||||
{
|
||||
mWindowManager.removeGuiMode (GM_Dialogue);
|
||||
mWindowManager.removeGuiMode (GM_Enchanting);
|
||||
}
|
||||
|
||||
void EnchantingDialog::onCancelButtonClicked(MyGUI::Widget* sender)
|
||||
{
|
||||
mWindowManager.removeGuiMode (GM_Enchanting);
|
||||
}
|
||||
}
|
31
apps/openmw/mwgui/enchantingdialog.hpp
Normal file
31
apps/openmw/mwgui/enchantingdialog.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef MWGUI_ENCHANTINGDIALOG_H
|
||||
#define MWGUI_ENCHANTINGDIALOG_H
|
||||
|
||||
#include "window_base.hpp"
|
||||
#include "referenceinterface.hpp"
|
||||
#include "spellcreationdialog.hpp"
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
class EnchantingDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase
|
||||
{
|
||||
public:
|
||||
EnchantingDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
||||
virtual void open();
|
||||
void startEnchanting(MWWorld::Ptr actor);
|
||||
|
||||
protected:
|
||||
virtual void onReferenceUnavailable();
|
||||
|
||||
void onCancelButtonClicked(MyGUI::Widget* sender);
|
||||
|
||||
MyGUI::Button* mCancelButton;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -245,15 +245,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender)
|
|||
return;
|
||||
|
||||
std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle();
|
||||
MWWorld::Ptr object;
|
||||
try
|
||||
{
|
||||
object = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle);
|
||||
}
|
||||
catch (std::exception& /* e */)
|
||||
{
|
||||
return;
|
||||
}
|
||||
MWWorld::Ptr object = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle);
|
||||
|
||||
if (mode == GM_Console)
|
||||
MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object);
|
||||
|
|
|
@ -85,6 +85,7 @@ MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager)
|
|||
: WindowBase("openmw_journal.layout", parWindowManager)
|
||||
, mLastPos(0)
|
||||
, mVisible(false)
|
||||
, mPageNumber(0)
|
||||
{
|
||||
//setCoord(0,0,498, 342);
|
||||
center();
|
||||
|
|
|
@ -128,4 +128,10 @@ void MWList::onItemSelected(MyGUI::Widget* _sender)
|
|||
std::string name = static_cast<MyGUI::Button*>(_sender)->getCaption();
|
||||
|
||||
eventItemSelected(name);
|
||||
eventWidgetSelected(_sender);
|
||||
}
|
||||
|
||||
MyGUI::Widget* MWList::getItemWidget(const std::string& name)
|
||||
{
|
||||
return mScrollView->findWidget (getName() + "_item_" + name);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace MWGui
|
|||
MWList();
|
||||
|
||||
typedef MyGUI::delegates::CMultiDelegate1<std::string> EventHandle_String;
|
||||
typedef MyGUI::delegates::CMultiDelegate1<MyGUI::Widget*> EventHandle_Widget;
|
||||
|
||||
/**
|
||||
* Event: Item selected with the mouse.
|
||||
|
@ -25,6 +26,13 @@ namespace MWGui
|
|||
*/
|
||||
EventHandle_String eventItemSelected;
|
||||
|
||||
/**
|
||||
* Event: Item selected with the mouse.
|
||||
* signature: void method(MyGUI::Widget* sender)
|
||||
*/
|
||||
EventHandle_Widget eventWidgetSelected;
|
||||
|
||||
|
||||
/**
|
||||
* Call after the size of the list changed, or items were inserted/removed
|
||||
*/
|
||||
|
@ -38,6 +46,9 @@ namespace MWGui
|
|||
std::string getItemNameAt(unsigned int at); ///< \attention if there are separators, this method will return "" at the place where the separator is
|
||||
void clear();
|
||||
|
||||
MyGUI::Widget* getItemWidget(const std::string& name);
|
||||
///< get widget for an item name, useful to set up tooltip
|
||||
|
||||
protected:
|
||||
void initialiseOverride();
|
||||
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
#include <OgreCompositorChain.h>
|
||||
#include <OgreMaterial.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <openengine/ogre/fader.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/inputmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
|
@ -106,6 +109,7 @@ namespace MWGui
|
|||
|
||||
if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f)
|
||||
{
|
||||
float dt = mTimer.getMilliseconds () - mLastRenderTime;
|
||||
mLastRenderTime = mTimer.getMilliseconds ();
|
||||
|
||||
if (mFirstLoad && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 3000*1)
|
||||
|
@ -151,6 +155,8 @@ namespace MWGui
|
|||
}
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getWorld ()->getFader ()->update (dt);
|
||||
|
||||
mWindow->update();
|
||||
|
||||
if (!hasCompositor)
|
||||
|
@ -207,20 +213,22 @@ namespace MWGui
|
|||
|
||||
void LoadingScreen::changeWallpaper ()
|
||||
{
|
||||
/// \todo use a directory listing here
|
||||
std::vector<std::string> splash;
|
||||
splash.push_back ("Splash_Bonelord.tga");
|
||||
splash.push_back ("Splash_ClannDaddy.tga");
|
||||
splash.push_back ("Splash_Clannfear.tga");
|
||||
splash.push_back ("Splash_Daedroth.tga");
|
||||
splash.push_back ("Splash_Hunger.tga");
|
||||
splash.push_back ("Splash_KwamaWarrior.tga");
|
||||
splash.push_back ("Splash_Netch.tga");
|
||||
splash.push_back ("Splash_NixHound.tga");
|
||||
splash.push_back ("Splash_Siltstriker.tga");
|
||||
splash.push_back ("Splash_Skeleton.tga");
|
||||
splash.push_back ("Splash_SphereCenturion.tga");
|
||||
|
||||
mBackgroundImage->setImageTexture (splash[rand() % splash.size()]);
|
||||
Ogre::StringVectorPtr resources = Ogre::ResourceGroupManager::getSingleton ().listResourceNames ("General", false);
|
||||
for (Ogre::StringVector::const_iterator it = resources->begin(); it != resources->end(); ++it)
|
||||
{
|
||||
if (it->size() < 6)
|
||||
continue;
|
||||
std::string start = it->substr(0, 6);
|
||||
boost::to_lower(start);
|
||||
|
||||
if (start == "splash")
|
||||
splash.push_back (*it);
|
||||
}
|
||||
std::string randomSplash = splash[rand() % splash.size()];
|
||||
|
||||
Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General");
|
||||
mBackgroundImage->setImageTexture (randomSplash);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,10 @@ namespace MWGui
|
|||
GM_Rest,
|
||||
GM_RestBed,
|
||||
GM_SpellBuying,
|
||||
GM_Travel,
|
||||
GM_SpellCreation,
|
||||
GM_Enchanting,
|
||||
GM_Training,
|
||||
|
||||
GM_Levelup,
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager)
|
|||
getWidget(okButton, "OKButton");
|
||||
okButton->setCaption(mWindowManager.getGameSettingString("sOK", ""));
|
||||
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked);
|
||||
okButton->setEnabled(false);
|
||||
|
||||
updateRaces();
|
||||
updateSkills();
|
||||
|
@ -121,6 +122,9 @@ void RaceDialog::setRaceId(const std::string &raceId)
|
|||
if (boost::iequals(*mRaceList->getItemDataAt<std::string>(i), raceId))
|
||||
{
|
||||
mRaceList->setIndexSelected(i);
|
||||
MyGUI::ButtonPtr okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
okButton->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +153,8 @@ void RaceDialog::close()
|
|||
|
||||
void RaceDialog::onOkClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
eventDone(this);
|
||||
}
|
||||
|
||||
|
@ -200,6 +206,9 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index)
|
|||
if (_index == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
|
||||
MyGUI::ButtonPtr okButton;
|
||||
getWidget(okButton, "OKButton");
|
||||
okButton->setEnabled(true);
|
||||
const std::string *raceId = mRaceList->getItemDataAt<std::string>(_index);
|
||||
if (boost::iequals(mCurrentRaceId, *raceId))
|
||||
return;
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace MWGui
|
|||
|
||||
SpellBuyingWindow::SpellBuyingWindow(MWBase::WindowManager& parWindowManager) :
|
||||
WindowBase("openmw_spell_buying_window.layout", parWindowManager)
|
||||
, ContainerBase(NULL) // no drag&drop
|
||||
, mCurrentY(0)
|
||||
, mLastPos(0)
|
||||
{
|
||||
|
@ -55,7 +54,7 @@ namespace MWGui
|
|||
|
||||
MyGUI::Button* toAdd =
|
||||
mSpellsView->createWidget<MyGUI::Button>(
|
||||
(price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SpellText",
|
||||
(price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton",
|
||||
0,
|
||||
mCurrentY,
|
||||
200,
|
||||
|
@ -88,7 +87,7 @@ namespace MWGui
|
|||
void SpellBuyingWindow::startSpellBuying(const MWWorld::Ptr& actor)
|
||||
{
|
||||
center();
|
||||
mActor = actor;
|
||||
mPtr = actor;
|
||||
clearSpells();
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
@ -125,7 +124,7 @@ namespace MWGui
|
|||
MWMechanics::Spells& spells = stats.getSpells();
|
||||
spells.add (mSpellsWidgetMap.find(_sender)->second);
|
||||
mWindowManager.getTradeWindow()->addOrRemoveGold(-price);
|
||||
startSpellBuying(mActor);
|
||||
startSpellBuying(mPtr);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#ifndef MWGUI_SpellBuyingWINDOW_H
|
||||
#define MWGUI_SpellBuyingWINDOW_H
|
||||
|
||||
#include "container.hpp"
|
||||
#include "window_base.hpp"
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "referenceinterface.hpp"
|
||||
|
||||
namespace MyGUI
|
||||
{
|
||||
|
@ -20,7 +18,7 @@ namespace MWGui
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
class SpellBuyingWindow : public ContainerBase, public WindowBase
|
||||
class SpellBuyingWindow : public ReferenceInterface, public WindowBase
|
||||
{
|
||||
public:
|
||||
SpellBuyingWindow(MWBase::WindowManager& parWindowManager);
|
||||
|
@ -35,8 +33,6 @@ namespace MWGui
|
|||
|
||||
MyGUI::ScrollView* mSpellsView;
|
||||
|
||||
MWWorld::Ptr mActor;
|
||||
|
||||
std::map<MyGUI::Widget*, std::string> mSpellsWidgetMap;
|
||||
|
||||
void onCancelButtonClicked(MyGUI::Widget* _sender);
|
||||
|
|
619
apps/openmw/mwgui/spellcreationdialog.cpp
Normal file
619
apps/openmw/mwgui/spellcreationdialog.cpp
Normal file
|
@ -0,0 +1,619 @@
|
|||
#include "spellcreationdialog.hpp"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <components/esm_store/store.hpp>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "../mwmechanics/spells.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/spellsuccess.hpp"
|
||||
|
||||
|
||||
#include "tooltips.hpp"
|
||||
#include "widgets.hpp"
|
||||
#include "class.hpp"
|
||||
#include "inventorywindow.hpp"
|
||||
#include "tradewindow.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool sortMagicEffects (short id1, short id2)
|
||||
{
|
||||
return MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find(ESM::MagicEffect::effectIdToString (id1))->getString()
|
||||
< MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find(ESM::MagicEffect::effectIdToString (id2))->getString();
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
EditEffectDialog::EditEffectDialog(MWBase::WindowManager &parWindowManager)
|
||||
: WindowModal("openmw_edit_effect.layout", parWindowManager)
|
||||
, mEditing(false)
|
||||
{
|
||||
getWidget(mCancelButton, "CancelButton");
|
||||
getWidget(mOkButton, "OkButton");
|
||||
getWidget(mDeleteButton, "DeleteButton");
|
||||
getWidget(mRangeButton, "RangeButton");
|
||||
getWidget(mMagnitudeMinValue, "MagnitudeMinValue");
|
||||
getWidget(mMagnitudeMaxValue, "MagnitudeMaxValue");
|
||||
getWidget(mDurationValue, "DurationValue");
|
||||
getWidget(mAreaValue, "AreaValue");
|
||||
getWidget(mMagnitudeMinSlider, "MagnitudeMinSlider");
|
||||
getWidget(mMagnitudeMaxSlider, "MagnitudeMaxSlider");
|
||||
getWidget(mDurationSlider, "DurationSlider");
|
||||
getWidget(mAreaSlider, "AreaSlider");
|
||||
getWidget(mEffectImage, "EffectImage");
|
||||
getWidget(mEffectName, "EffectName");
|
||||
getWidget(mAreaText, "AreaText");
|
||||
getWidget(mDurationBox, "DurationBox");
|
||||
getWidget(mAreaBox, "AreaBox");
|
||||
getWidget(mMagnitudeBox, "MagnitudeBox");
|
||||
|
||||
mRangeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditEffectDialog::onRangeButtonClicked);
|
||||
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditEffectDialog::onOkButtonClicked);
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditEffectDialog::onCancelButtonClicked);
|
||||
mDeleteButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EditEffectDialog::onDeleteButtonClicked);
|
||||
|
||||
mMagnitudeMinSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMinChanged);
|
||||
mMagnitudeMaxSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMaxChanged);
|
||||
mDurationSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onDurationChanged);
|
||||
mAreaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onAreaChanged);
|
||||
}
|
||||
|
||||
void EditEffectDialog::open()
|
||||
{
|
||||
WindowModal::open();
|
||||
center();
|
||||
}
|
||||
|
||||
void EditEffectDialog::newEffect (const ESM::MagicEffect *effect)
|
||||
{
|
||||
setMagicEffect(effect);
|
||||
mEditing = false;
|
||||
|
||||
mDeleteButton->setVisible (false);
|
||||
|
||||
mEffect.mRange = ESM::RT_Self;
|
||||
|
||||
onRangeButtonClicked(mRangeButton);
|
||||
|
||||
mMagnitudeMinSlider->setScrollPosition (0);
|
||||
mMagnitudeMaxSlider->setScrollPosition (0);
|
||||
mAreaSlider->setScrollPosition (0);
|
||||
mDurationSlider->setScrollPosition (0);
|
||||
|
||||
mDurationValue->setCaption("1");
|
||||
mMagnitudeMinValue->setCaption("1");
|
||||
mMagnitudeMaxValue->setCaption("- 1");
|
||||
mAreaValue->setCaption("0");
|
||||
|
||||
mEffect.mMagnMin = 1;
|
||||
mEffect.mMagnMax = 1;
|
||||
mEffect.mDuration = 1;
|
||||
mEffect.mArea = 0;
|
||||
}
|
||||
|
||||
void EditEffectDialog::editEffect (ESM::ENAMstruct effect)
|
||||
{
|
||||
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(effect.mEffectID);
|
||||
|
||||
setMagicEffect(magicEffect);
|
||||
|
||||
mEffect = effect;
|
||||
mEditing = true;
|
||||
|
||||
mDeleteButton->setVisible (true);
|
||||
|
||||
mMagnitudeMinSlider->setScrollPosition (effect.mMagnMin-1);
|
||||
mMagnitudeMaxSlider->setScrollPosition (effect.mMagnMax-1);
|
||||
mAreaSlider->setScrollPosition (effect.mArea);
|
||||
mDurationSlider->setScrollPosition (effect.mDuration-1);
|
||||
|
||||
onMagnitudeMinChanged (mMagnitudeMinSlider, effect.mMagnMin-1);
|
||||
onMagnitudeMaxChanged (mMagnitudeMinSlider, effect.mMagnMax-1);
|
||||
onAreaChanged (mAreaSlider, effect.mArea);
|
||||
onDurationChanged (mDurationSlider, effect.mDuration-1);
|
||||
}
|
||||
|
||||
void EditEffectDialog::setMagicEffect (const ESM::MagicEffect *effect)
|
||||
{
|
||||
std::string icon = effect->mIcon;
|
||||
icon[icon.size()-3] = 'd';
|
||||
icon[icon.size()-2] = 'd';
|
||||
icon[icon.size()-1] = 's';
|
||||
icon = "icons\\" + icon;
|
||||
|
||||
mEffectImage->setImageTexture (icon);
|
||||
|
||||
mEffectName->setCaptionWithReplacing("#{"+ESM::MagicEffect::effectIdToString (effect->mIndex)+"}");
|
||||
|
||||
mEffect.mEffectID = effect->mIndex;
|
||||
|
||||
mMagicEffect = effect;
|
||||
|
||||
updateBoxes();
|
||||
}
|
||||
|
||||
void EditEffectDialog::updateBoxes()
|
||||
{
|
||||
static int startY = mMagnitudeBox->getPosition().top;
|
||||
int curY = startY;
|
||||
|
||||
mMagnitudeBox->setVisible (false);
|
||||
mDurationBox->setVisible (false);
|
||||
mAreaBox->setVisible (false);
|
||||
|
||||
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
|
||||
{
|
||||
mMagnitudeBox->setPosition(mMagnitudeBox->getPosition().left, curY);
|
||||
mMagnitudeBox->setVisible (true);
|
||||
curY += mMagnitudeBox->getSize().height;
|
||||
}
|
||||
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||
{
|
||||
mDurationBox->setPosition(mDurationBox->getPosition().left, curY);
|
||||
mDurationBox->setVisible (true);
|
||||
curY += mDurationBox->getSize().height;
|
||||
}
|
||||
if (mEffect.mRange == ESM::RT_Target)
|
||||
{
|
||||
mAreaBox->setPosition(mAreaBox->getPosition().left, curY);
|
||||
mAreaBox->setVisible (true);
|
||||
curY += mAreaBox->getSize().height;
|
||||
}
|
||||
}
|
||||
|
||||
void EditEffectDialog::onRangeButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
mEffect.mRange = (mEffect.mRange+1)%3;
|
||||
|
||||
if (mEffect.mRange == ESM::RT_Self)
|
||||
mRangeButton->setCaptionWithReplacing ("#{sRangeSelf}");
|
||||
else if (mEffect.mRange == ESM::RT_Target)
|
||||
mRangeButton->setCaptionWithReplacing ("#{sRangeTarget}");
|
||||
else if (mEffect.mRange == ESM::RT_Touch)
|
||||
mRangeButton->setCaptionWithReplacing ("#{sRangeTouch}");
|
||||
|
||||
mAreaSlider->setVisible (mEffect.mRange != ESM::RT_Self);
|
||||
mAreaText->setVisible (mEffect.mRange != ESM::RT_Self);
|
||||
|
||||
// cycle through range types until we find something that's allowed
|
||||
if (mEffect.mRange == ESM::RT_Target && !(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget))
|
||||
onRangeButtonClicked(sender);
|
||||
if (mEffect.mRange == ESM::RT_Self && !(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf))
|
||||
onRangeButtonClicked(sender);
|
||||
if (mEffect.mRange == ESM::RT_Touch && !(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch))
|
||||
onRangeButtonClicked(sender);
|
||||
|
||||
updateBoxes();
|
||||
}
|
||||
|
||||
void EditEffectDialog::onDeleteButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
setVisible(false);
|
||||
|
||||
eventEffectRemoved(mEffect);
|
||||
}
|
||||
|
||||
void EditEffectDialog::onOkButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
setVisible(false);
|
||||
|
||||
if (mEditing)
|
||||
eventEffectModified(mEffect);
|
||||
else
|
||||
eventEffectAdded(mEffect);
|
||||
}
|
||||
|
||||
void EditEffectDialog::onCancelButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
void EditEffectDialog::setSkill (int skill)
|
||||
{
|
||||
mEffect.mSkill = skill;
|
||||
}
|
||||
|
||||
void EditEffectDialog::setAttribute (int attribute)
|
||||
{
|
||||
mEffect.mAttribute = attribute;
|
||||
}
|
||||
|
||||
void EditEffectDialog::onMagnitudeMinChanged (MyGUI::ScrollBar* sender, size_t pos)
|
||||
{
|
||||
mMagnitudeMinValue->setCaption(boost::lexical_cast<std::string>(pos+1));
|
||||
mEffect.mMagnMin = pos+1;
|
||||
|
||||
// trigger the check again (see below)
|
||||
onMagnitudeMaxChanged(mMagnitudeMaxSlider, mMagnitudeMaxSlider->getScrollPosition ());
|
||||
}
|
||||
|
||||
void EditEffectDialog::onMagnitudeMaxChanged (MyGUI::ScrollBar* sender, size_t pos)
|
||||
{
|
||||
// make sure the max value is actually larger or equal than the min value
|
||||
size_t magnMin = std::abs(mEffect.mMagnMin); // should never be < 0, this is just here to avoid the compiler warning
|
||||
if (pos+1 < magnMin)
|
||||
{
|
||||
pos = mEffect.mMagnMin-1;
|
||||
sender->setScrollPosition (pos);
|
||||
}
|
||||
|
||||
mEffect.mMagnMax = pos+1;
|
||||
|
||||
mMagnitudeMaxValue->setCaption("- " + boost::lexical_cast<std::string>(pos+1));
|
||||
}
|
||||
|
||||
void EditEffectDialog::onDurationChanged (MyGUI::ScrollBar* sender, size_t pos)
|
||||
{
|
||||
mDurationValue->setCaption(boost::lexical_cast<std::string>(pos+1));
|
||||
mEffect.mDuration = pos+1;
|
||||
}
|
||||
|
||||
void EditEffectDialog::onAreaChanged (MyGUI::ScrollBar* sender, size_t pos)
|
||||
{
|
||||
mAreaValue->setCaption(boost::lexical_cast<std::string>(pos));
|
||||
mEffect.mArea = pos;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
SpellCreationDialog::SpellCreationDialog(MWBase::WindowManager &parWindowManager)
|
||||
: WindowBase("openmw_spellcreation_dialog.layout", parWindowManager)
|
||||
, EffectEditorBase(parWindowManager)
|
||||
{
|
||||
getWidget(mNameEdit, "NameEdit");
|
||||
getWidget(mMagickaCost, "MagickaCost");
|
||||
getWidget(mSuccessChance, "SuccessChance");
|
||||
getWidget(mAvailableEffectsList, "AvailableEffects");
|
||||
getWidget(mUsedEffectsView, "UsedEffects");
|
||||
getWidget(mPriceLabel, "PriceLabel");
|
||||
getWidget(mBuyButton, "BuyButton");
|
||||
getWidget(mCancelButton, "CancelButton");
|
||||
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onCancelButtonClicked);
|
||||
mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onBuyButtonClicked);
|
||||
|
||||
setWidgets(mAvailableEffectsList, mUsedEffectsView);
|
||||
}
|
||||
|
||||
void SpellCreationDialog::startSpellMaking (MWWorld::Ptr actor)
|
||||
{
|
||||
mPtr = actor;
|
||||
mNameEdit->setCaption("");
|
||||
|
||||
startEditing();
|
||||
}
|
||||
|
||||
void SpellCreationDialog::onCancelButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
mWindowManager.removeGuiMode (MWGui::GM_SpellCreation);
|
||||
}
|
||||
|
||||
void SpellCreationDialog::onBuyButtonClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
if (mEffects.size() <= 0)
|
||||
{
|
||||
mWindowManager.messageBox ("#{sNotifyMessage30}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
if (mNameEdit->getCaption () == "")
|
||||
{
|
||||
mWindowManager.messageBox ("#{sNotifyMessage10}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
if (mMagickaCost->getCaption() == "0")
|
||||
{
|
||||
mWindowManager.messageBox ("#{sEnchantmentMenu8}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
if (boost::lexical_cast<int>(mPriceLabel->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold())
|
||||
{
|
||||
mWindowManager.messageBox ("#{sNotifyMessage18}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
mSpell.mName = mNameEdit->getCaption();
|
||||
|
||||
mWindowManager.getTradeWindow()->addOrRemoveGold(-boost::lexical_cast<int>(mPriceLabel->getCaption()));
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
|
||||
|
||||
std::pair<std::string, const ESM::Spell*> result = MWBase::Environment::get().getWorld()->createRecord(mSpell);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||
MWMechanics::Spells& spells = stats.getSpells();
|
||||
spells.add (result.first);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0);
|
||||
|
||||
mWindowManager.removeGuiMode (GM_SpellCreation);
|
||||
}
|
||||
|
||||
void SpellCreationDialog::open()
|
||||
{
|
||||
center();
|
||||
}
|
||||
|
||||
void SpellCreationDialog::onReferenceUnavailable ()
|
||||
{
|
||||
mWindowManager.removeGuiMode (GM_Dialogue);
|
||||
mWindowManager.removeGuiMode (GM_SpellCreation);
|
||||
}
|
||||
|
||||
void SpellCreationDialog::notifyEffectsChanged ()
|
||||
{
|
||||
float y = 0;
|
||||
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||
{
|
||||
float x = 0.5 * it->mMagnMin + it->mMagnMax;
|
||||
|
||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(it->mEffectID);
|
||||
x *= 0.1 * effect->mData.mBaseCost;
|
||||
x *= 1 + it->mDuration;
|
||||
x += 0.05 * std::max(1, it->mArea) * effect->mData.mBaseCost;
|
||||
|
||||
float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fEffectCostMult")->getFloat();
|
||||
y += x * fEffectCostMult;
|
||||
y = std::max(1.f,y);
|
||||
|
||||
if (effect->mData.mFlags & ESM::MagicEffect::CastTarget)
|
||||
y *= 1.5;
|
||||
}
|
||||
|
||||
mSpell.mData.mCost = int(y);
|
||||
|
||||
ESM::EffectList effectList;
|
||||
effectList.mList = mEffects;
|
||||
mSpell.mEffects = effectList;
|
||||
mSpell.mData.mType = ESM::Spell::ST_Spell;
|
||||
|
||||
mMagickaCost->setCaption(boost::lexical_cast<std::string>(int(y)));
|
||||
|
||||
float fSpellMakingValueMult = MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fSpellMakingValueMult")->getFloat();
|
||||
|
||||
/// \todo mercantile
|
||||
int price = int(y) * fSpellMakingValueMult;
|
||||
|
||||
mPriceLabel->setCaption(boost::lexical_cast<std::string>(int(price)));
|
||||
|
||||
float chance = MWMechanics::getSpellSuccessChance(&mSpell, MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
|
||||
mSuccessChance->setCaption(boost::lexical_cast<std::string>(int(chance)));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
EffectEditorBase::EffectEditorBase(MWBase::WindowManager& parWindowManager)
|
||||
: mAddEffectDialog(parWindowManager)
|
||||
, mSelectAttributeDialog(NULL)
|
||||
, mSelectSkillDialog(NULL)
|
||||
{
|
||||
mAddEffectDialog.eventEffectAdded += MyGUI::newDelegate(this, &EffectEditorBase::onEffectAdded);
|
||||
mAddEffectDialog.eventEffectModified += MyGUI::newDelegate(this, &EffectEditorBase::onEffectModified);
|
||||
mAddEffectDialog.eventEffectRemoved += MyGUI::newDelegate(this, &EffectEditorBase::onEffectRemoved);
|
||||
|
||||
mAddEffectDialog.setVisible (false);
|
||||
}
|
||||
|
||||
void EffectEditorBase::startEditing ()
|
||||
{
|
||||
// get the list of magic effects that are known to the player
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
|
||||
MWMechanics::Spells& spells = stats.getSpells();
|
||||
|
||||
std::vector<short> knownEffects;
|
||||
|
||||
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||
{
|
||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(*it);
|
||||
|
||||
// only normal spells count
|
||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||
continue;
|
||||
|
||||
const std::vector<ESM::ENAMstruct>& list = spell->mEffects.mList;
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it2 = list.begin(); it2 != list.end(); ++it2)
|
||||
{
|
||||
if (std::find(knownEffects.begin(), knownEffects.end(), it2->mEffectID) == knownEffects.end())
|
||||
knownEffects.push_back(it2->mEffectID);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(knownEffects.begin(), knownEffects.end(), sortMagicEffects);
|
||||
|
||||
mAvailableEffectsList->clear ();
|
||||
|
||||
for (std::vector<short>::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it)
|
||||
{
|
||||
mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find(
|
||||
ESM::MagicEffect::effectIdToString (*it))->getString());
|
||||
}
|
||||
mAvailableEffectsList->adjustSize ();
|
||||
|
||||
for (std::vector<short>::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it)
|
||||
{
|
||||
std::string name = MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find(
|
||||
ESM::MagicEffect::effectIdToString (*it))->getString();
|
||||
MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name);
|
||||
w->setUserData(*it);
|
||||
|
||||
ToolTips::createMagicEffectToolTip (w, *it);
|
||||
}
|
||||
|
||||
mEffects.clear();
|
||||
updateEffectsView ();
|
||||
}
|
||||
|
||||
void EffectEditorBase::setWidgets (Widgets::MWList *availableEffectsList, MyGUI::ScrollView *usedEffectsView)
|
||||
{
|
||||
mAvailableEffectsList = availableEffectsList;
|
||||
mUsedEffectsView = usedEffectsView;
|
||||
|
||||
mAvailableEffectsList->eventWidgetSelected += MyGUI::newDelegate(this, &EffectEditorBase::onAvailableEffectClicked);
|
||||
}
|
||||
|
||||
void EffectEditorBase::onSelectAttribute ()
|
||||
{
|
||||
mAddEffectDialog.setVisible(true);
|
||||
mAddEffectDialog.setAttribute (mSelectAttributeDialog->getAttributeId());
|
||||
MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectAttributeDialog);
|
||||
mSelectAttributeDialog = 0;
|
||||
}
|
||||
|
||||
void EffectEditorBase::onSelectSkill ()
|
||||
{
|
||||
mAddEffectDialog.setVisible(true);
|
||||
mAddEffectDialog.setSkill (mSelectSkillDialog->getSkillId ());
|
||||
MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectSkillDialog);
|
||||
mSelectSkillDialog = 0;
|
||||
}
|
||||
|
||||
void EffectEditorBase::onAttributeOrSkillCancel ()
|
||||
{
|
||||
if (mSelectSkillDialog)
|
||||
MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectSkillDialog);
|
||||
if (mSelectAttributeDialog)
|
||||
MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectAttributeDialog);
|
||||
|
||||
mSelectSkillDialog = 0;
|
||||
mSelectAttributeDialog = 0;
|
||||
}
|
||||
|
||||
void EffectEditorBase::onAvailableEffectClicked (MyGUI::Widget* sender)
|
||||
{
|
||||
if (mEffects.size() >= 8)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage28}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
short effectId = *sender->getUserData<short>();
|
||||
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||
{
|
||||
if (it->mEffectID == effectId)
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(effectId);
|
||||
|
||||
mAddEffectDialog.newEffect (effect);
|
||||
|
||||
if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||
{
|
||||
delete mSelectSkillDialog;
|
||||
mSelectSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager ());
|
||||
mSelectSkillDialog->eventCancel += MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel);
|
||||
mSelectSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &SpellCreationDialog::onSelectSkill);
|
||||
mSelectSkillDialog->setVisible (true);
|
||||
}
|
||||
else if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
||||
{
|
||||
delete mSelectAttributeDialog;
|
||||
mSelectAttributeDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager ());
|
||||
mSelectAttributeDialog->eventCancel += MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel);
|
||||
mSelectAttributeDialog->eventItemSelected += MyGUI::newDelegate(this, &SpellCreationDialog::onSelectAttribute);
|
||||
mSelectAttributeDialog->setVisible (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
mAddEffectDialog.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectEditorBase::onEffectModified (ESM::ENAMstruct effect)
|
||||
{
|
||||
mEffects[mSelectedEffect] = effect;
|
||||
|
||||
updateEffectsView();
|
||||
}
|
||||
|
||||
void EffectEditorBase::onEffectRemoved (ESM::ENAMstruct effect)
|
||||
{
|
||||
mEffects.erase(mEffects.begin() + mSelectedEffect);
|
||||
updateEffectsView();
|
||||
}
|
||||
|
||||
void EffectEditorBase::updateEffectsView ()
|
||||
{
|
||||
MyGUI::EnumeratorWidgetPtr oldWidgets = mUsedEffectsView->getEnumerator ();
|
||||
MyGUI::Gui::getInstance ().destroyWidgets (oldWidgets);
|
||||
|
||||
MyGUI::IntSize size(0,0);
|
||||
|
||||
int i = 0;
|
||||
for (std::vector<ESM::ENAMstruct>::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it)
|
||||
{
|
||||
Widgets::SpellEffectParams params;
|
||||
params.mEffectID = it->mEffectID;
|
||||
params.mSkill = it->mSkill;
|
||||
params.mAttribute = it->mAttribute;
|
||||
params.mDuration = it->mDuration;
|
||||
params.mMagnMin = it->mMagnMin;
|
||||
params.mMagnMax = it->mMagnMax;
|
||||
params.mRange = it->mRange;
|
||||
params.mArea = it->mArea;
|
||||
|
||||
MyGUI::Button* button = mUsedEffectsView->createWidget<MyGUI::Button>("", MyGUI::IntCoord(0, size.height, 0, 24), MyGUI::Align::Default);
|
||||
button->setUserData(i);
|
||||
button->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellCreationDialog::onEditEffect);
|
||||
button->setNeedMouseFocus (true);
|
||||
|
||||
Widgets::MWSpellEffectPtr effect = button->createWidget<Widgets::MWSpellEffect>("MW_EffectImage", MyGUI::IntCoord(0,0,0,24), MyGUI::Align::Default);
|
||||
|
||||
effect->setNeedMouseFocus (false);
|
||||
effect->setWindowManager (MWBase::Environment::get().getWindowManager ());
|
||||
effect->setSpellEffect (params);
|
||||
|
||||
effect->setSize(effect->getRequestedWidth (), 24);
|
||||
button->setSize(effect->getRequestedWidth (), 24);
|
||||
|
||||
size.width = std::max(size.width, effect->getRequestedWidth ());
|
||||
size.height += 24;
|
||||
++i;
|
||||
}
|
||||
|
||||
mUsedEffectsView->setCanvasSize(size);
|
||||
|
||||
notifyEffectsChanged();
|
||||
}
|
||||
|
||||
void EffectEditorBase::onEffectAdded (ESM::ENAMstruct effect)
|
||||
{
|
||||
mEffects.push_back(effect);
|
||||
|
||||
updateEffectsView();
|
||||
}
|
||||
|
||||
void EffectEditorBase::onEditEffect (MyGUI::Widget *sender)
|
||||
{
|
||||
int id = *sender->getUserData<int>();
|
||||
|
||||
mSelectedEffect = id;
|
||||
|
||||
mAddEffectDialog.editEffect (mEffects[id]);
|
||||
mAddEffectDialog.setVisible (true);
|
||||
}
|
||||
}
|
154
apps/openmw/mwgui/spellcreationdialog.hpp
Normal file
154
apps/openmw/mwgui/spellcreationdialog.hpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
#ifndef MWGUI_SPELLCREATION_H
|
||||
#define MWGUI_SPELLCREATION_H
|
||||
|
||||
#include "window_base.hpp"
|
||||
#include "referenceinterface.hpp"
|
||||
#include "list.hpp"
|
||||
#include "widgets.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
class SelectSkillDialog;
|
||||
class SelectAttributeDialog;
|
||||
|
||||
class EditEffectDialog : public WindowModal
|
||||
{
|
||||
public:
|
||||
EditEffectDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
||||
virtual void open();
|
||||
|
||||
void setSkill(int skill);
|
||||
void setAttribute(int attribute);
|
||||
|
||||
void newEffect (const ESM::MagicEffect* effect);
|
||||
void editEffect (ESM::ENAMstruct effect);
|
||||
|
||||
typedef MyGUI::delegates::CMultiDelegate1<ESM::ENAMstruct> EventHandle_Effect;
|
||||
|
||||
EventHandle_Effect eventEffectAdded;
|
||||
EventHandle_Effect eventEffectModified;
|
||||
EventHandle_Effect eventEffectRemoved;
|
||||
|
||||
protected:
|
||||
MyGUI::Button* mCancelButton;
|
||||
MyGUI::Button* mOkButton;
|
||||
MyGUI::Button* mDeleteButton;
|
||||
|
||||
MyGUI::Button* mRangeButton;
|
||||
|
||||
MyGUI::Widget* mDurationBox;
|
||||
MyGUI::Widget* mMagnitudeBox;
|
||||
MyGUI::Widget* mAreaBox;
|
||||
|
||||
MyGUI::TextBox* mMagnitudeMinValue;
|
||||
MyGUI::TextBox* mMagnitudeMaxValue;
|
||||
MyGUI::TextBox* mDurationValue;
|
||||
MyGUI::TextBox* mAreaValue;
|
||||
|
||||
MyGUI::ScrollBar* mMagnitudeMinSlider;
|
||||
MyGUI::ScrollBar* mMagnitudeMaxSlider;
|
||||
MyGUI::ScrollBar* mDurationSlider;
|
||||
MyGUI::ScrollBar* mAreaSlider;
|
||||
|
||||
MyGUI::TextBox* mAreaText;
|
||||
|
||||
MyGUI::ImageBox* mEffectImage;
|
||||
MyGUI::TextBox* mEffectName;
|
||||
|
||||
bool mEditing;
|
||||
|
||||
protected:
|
||||
void onRangeButtonClicked (MyGUI::Widget* sender);
|
||||
void onDeleteButtonClicked (MyGUI::Widget* sender);
|
||||
void onOkButtonClicked (MyGUI::Widget* sender);
|
||||
void onCancelButtonClicked (MyGUI::Widget* sender);
|
||||
|
||||
void onMagnitudeMinChanged (MyGUI::ScrollBar* sender, size_t pos);
|
||||
void onMagnitudeMaxChanged (MyGUI::ScrollBar* sender, size_t pos);
|
||||
void onDurationChanged (MyGUI::ScrollBar* sender, size_t pos);
|
||||
void onAreaChanged (MyGUI::ScrollBar* sender, size_t pos);
|
||||
|
||||
void setMagicEffect(const ESM::MagicEffect* effect);
|
||||
|
||||
void updateBoxes();
|
||||
|
||||
protected:
|
||||
ESM::ENAMstruct mEffect;
|
||||
|
||||
const ESM::MagicEffect* mMagicEffect;
|
||||
};
|
||||
|
||||
|
||||
class EffectEditorBase
|
||||
{
|
||||
public:
|
||||
EffectEditorBase(MWBase::WindowManager& parWindowManager);
|
||||
|
||||
|
||||
protected:
|
||||
Widgets::MWList* mAvailableEffectsList;
|
||||
MyGUI::ScrollView* mUsedEffectsView;
|
||||
|
||||
EditEffectDialog mAddEffectDialog;
|
||||
SelectAttributeDialog* mSelectAttributeDialog;
|
||||
SelectSkillDialog* mSelectSkillDialog;
|
||||
|
||||
int mSelectedEffect;
|
||||
|
||||
std::vector<ESM::ENAMstruct> mEffects;
|
||||
|
||||
void onEffectAdded(ESM::ENAMstruct effect);
|
||||
void onEffectModified(ESM::ENAMstruct effect);
|
||||
void onEffectRemoved(ESM::ENAMstruct effect);
|
||||
|
||||
void onAvailableEffectClicked (MyGUI::Widget* sender);
|
||||
|
||||
void onAttributeOrSkillCancel();
|
||||
void onSelectAttribute();
|
||||
void onSelectSkill();
|
||||
|
||||
void onEditEffect(MyGUI::Widget* sender);
|
||||
|
||||
void updateEffectsView();
|
||||
|
||||
void startEditing();
|
||||
void setWidgets (Widgets::MWList* availableEffectsList, MyGUI::ScrollView* usedEffectsView);
|
||||
|
||||
virtual void notifyEffectsChanged () {}
|
||||
};
|
||||
|
||||
class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase
|
||||
{
|
||||
public:
|
||||
SpellCreationDialog(MWBase::WindowManager& parWindowManager);
|
||||
|
||||
virtual void open();
|
||||
|
||||
void startSpellMaking(MWWorld::Ptr actor);
|
||||
|
||||
protected:
|
||||
virtual void onReferenceUnavailable ();
|
||||
|
||||
void onCancelButtonClicked (MyGUI::Widget* sender);
|
||||
void onBuyButtonClicked (MyGUI::Widget* sender);
|
||||
|
||||
virtual void notifyEffectsChanged ();
|
||||
|
||||
MyGUI::EditBox* mNameEdit;
|
||||
MyGUI::TextBox* mMagickaCost;
|
||||
MyGUI::TextBox* mSuccessChance;
|
||||
MyGUI::Button* mBuyButton;
|
||||
MyGUI::Button* mCancelButton;
|
||||
MyGUI::TextBox* mPriceLabel;
|
||||
|
||||
Widgets::MWEffectList* mUsedEffectsList;
|
||||
|
||||
ESM::Spell mSpell;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -67,7 +67,7 @@ StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager)
|
|||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
{
|
||||
mSkillValues.insert(std::pair<int, MWMechanics::Stat<float> >(i, MWMechanics::Stat<float>()));
|
||||
mSkillWidgetMap.insert(std::pair<int, MyGUI::TextBox*>(i, nullptr));
|
||||
mSkillWidgetMap.insert(std::pair<int, MyGUI::TextBox*>(i, (MyGUI::TextBox*)nullptr));
|
||||
}
|
||||
|
||||
MyGUI::WindowPtr t = static_cast<MyGUI::WindowPtr>(mMainWidget);
|
||||
|
|
|
@ -79,14 +79,10 @@ void ToolTips::onFrame(float frameDuration)
|
|||
|| (mWindowManager->getMode() == GM_Inventory)))
|
||||
{
|
||||
std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle();
|
||||
try
|
||||
{
|
||||
mFocusObject = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle);
|
||||
}
|
||||
catch (std::exception /* & e */)
|
||||
{
|
||||
|
||||
mFocusObject = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle);
|
||||
if (mFocusObject.isEmpty ())
|
||||
return;
|
||||
}
|
||||
|
||||
MyGUI::IntSize tooltipSize = getToolTipViaPtr(true);
|
||||
|
||||
|
@ -368,6 +364,9 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info)
|
|||
if (text.size() > 0 && text[0] == '\n')
|
||||
text.erase(0, 1);
|
||||
|
||||
if(caption.size() > 0 && isalnum(caption[0]))
|
||||
caption[0] = toupper(caption[0]);
|
||||
|
||||
const ESM::Enchantment* enchant = 0;
|
||||
const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
if (info.enchant != "")
|
||||
|
@ -588,8 +587,6 @@ void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId)
|
|||
widget->setUserString("Caption_SkillNoProgressDescription", skill->mDescription);
|
||||
widget->setUserString("Caption_SkillNoProgressAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}");
|
||||
widget->setUserString("ImageTexture_SkillNoProgressImage", icon);
|
||||
widget->setUserString("ToolTipLayout", "SkillNoProgressToolTip");
|
||||
widget->setUserString("ToolTipLayout", "SkillNoProgressToolTip");
|
||||
}
|
||||
|
||||
void ToolTips::createAttributeToolTip(MyGUI::Widget* widget, int attributeId)
|
||||
|
@ -715,6 +712,38 @@ void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playe
|
|||
widget->setUserString("ToolTipLayout", "ClassToolTip");
|
||||
}
|
||||
|
||||
void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id)
|
||||
{
|
||||
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld ()->getStore ().magicEffects.find(id);
|
||||
const std::string &name = ESM::MagicEffect::effectIdToString (id);
|
||||
|
||||
std::string icon = effect->mIcon;
|
||||
|
||||
int slashPos = icon.find("\\");
|
||||
icon.insert(slashPos+1, "b_");
|
||||
|
||||
icon[icon.size()-3] = 'd';
|
||||
icon[icon.size()-2] = 'd';
|
||||
icon[icon.size()-1] = 's';
|
||||
|
||||
icon = "icons\\" + icon;
|
||||
|
||||
std::vector<std::string> schools;
|
||||
schools.push_back ("#{sSchoolAlteration}");
|
||||
schools.push_back ("#{sSchoolConjuration}");
|
||||
schools.push_back ("#{sSchoolDestruction}");
|
||||
schools.push_back ("#{sSchoolIllusion}");
|
||||
schools.push_back ("#{sSchoolMysticism}");
|
||||
schools.push_back ("#{sSchoolRestoration}");
|
||||
|
||||
widget->setUserString("ToolTipType", "Layout");
|
||||
widget->setUserString("ToolTipLayout", "MagicEffectToolTip");
|
||||
widget->setUserString("Caption_MagicEffectName", "#{" + name + "}");
|
||||
widget->setUserString("Caption_MagicEffectDescription", effect->mDescription);
|
||||
widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + schools[effect->mData.mSchool]);
|
||||
widget->setUserString("ImageTexture_MagicEffectImage", icon);
|
||||
}
|
||||
|
||||
void ToolTips::setDelay(float delay)
|
||||
{
|
||||
mDelay = delay;
|
||||
|
|
|
@ -71,6 +71,7 @@ namespace MWGui
|
|||
static void createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId);
|
||||
static void createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace);
|
||||
static void createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass);
|
||||
static void createMagicEffectToolTip(MyGUI::Widget* widget, short id);
|
||||
|
||||
private:
|
||||
MyGUI::Widget* mDynamicToolTipBox;
|
||||
|
|
159
apps/openmw/mwgui/trainingwindow.cpp
Normal file
159
apps/openmw/mwgui/trainingwindow.cpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
#include "trainingwindow.hpp"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <openengine/ogre/fader.hpp>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
#include "inventorywindow.hpp"
|
||||
#include "tradewindow.hpp"
|
||||
#include "tooltips.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
TrainingWindow::TrainingWindow(MWBase::WindowManager &parWindowManager)
|
||||
: WindowBase("openmw_trainingwindow.layout", parWindowManager)
|
||||
, mFadeTimeRemaining(0)
|
||||
{
|
||||
getWidget(mTrainingOptions, "TrainingOptions");
|
||||
getWidget(mCancelButton, "CancelButton");
|
||||
getWidget(mPlayerGold, "PlayerGold");
|
||||
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onCancelButtonClicked);
|
||||
}
|
||||
|
||||
void TrainingWindow::open()
|
||||
{
|
||||
center();
|
||||
}
|
||||
|
||||
void TrainingWindow::startTraining (MWWorld::Ptr actor)
|
||||
{
|
||||
mPtr = actor;
|
||||
|
||||
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(mWindowManager.getInventoryWindow()->getPlayerGold()));
|
||||
|
||||
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(actor).getNpcStats (actor);
|
||||
|
||||
// NPC can train you in his best 3 skills
|
||||
std::vector< std::pair<int, int> > bestSkills;
|
||||
bestSkills.push_back (std::make_pair(-1, -1));
|
||||
bestSkills.push_back (std::make_pair(-1, -1));
|
||||
bestSkills.push_back (std::make_pair(-1, -1));
|
||||
|
||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||
{
|
||||
int value = npcStats.getSkill (i).getBase ();
|
||||
|
||||
for (int j=0; j<3; ++j)
|
||||
{
|
||||
if (value > bestSkills[j].second)
|
||||
{
|
||||
if (j<2)
|
||||
{
|
||||
bestSkills[j+1] = bestSkills[j];
|
||||
}
|
||||
bestSkills[j] = std::make_pair(i, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MyGUI::EnumeratorWidgetPtr widgets = mTrainingOptions->getEnumerator ();
|
||||
MyGUI::Gui::getInstance ().destroyWidgets (widgets);
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ();
|
||||
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
/// \todo mercantile skill
|
||||
int price = pcStats.getSkill (bestSkills[i].first).getBase() * MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find("iTrainingMod")->getInt ();
|
||||
|
||||
std::string skin = (price > mWindowManager.getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton";
|
||||
|
||||
MyGUI::Button* button = mTrainingOptions->createWidget<MyGUI::Button>(skin,
|
||||
MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default);
|
||||
|
||||
button->setUserData(bestSkills[i].first);
|
||||
button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected);
|
||||
|
||||
button->setCaptionWithReplacing("#{" + ESM::Skill::sSkillNameIds[bestSkills[i].first] + "} - " + boost::lexical_cast<std::string>(price));
|
||||
|
||||
button->setSize(button->getTextSize ().width+12, button->getSize().height);
|
||||
|
||||
ToolTips::createSkillToolTip (button, bestSkills[i].first);
|
||||
}
|
||||
|
||||
center();
|
||||
}
|
||||
|
||||
void TrainingWindow::onReferenceUnavailable ()
|
||||
{
|
||||
mWindowManager.removeGuiMode(GM_Training);
|
||||
}
|
||||
|
||||
void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender)
|
||||
{
|
||||
mWindowManager.removeGuiMode (GM_Training);
|
||||
}
|
||||
|
||||
void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender)
|
||||
{
|
||||
int skillId = *sender->getUserData<int>();
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ();
|
||||
MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player);
|
||||
|
||||
/// \todo mercantile skill
|
||||
int price = pcStats.getSkill (skillId).getBase() * MWBase::Environment::get().getWorld ()->getStore ().gameSettings.find("iTrainingMod")->getInt ();
|
||||
|
||||
if (mWindowManager.getInventoryWindow()->getPlayerGold()<price)
|
||||
return;
|
||||
|
||||
MWMechanics::NpcStats& npcStats = MWWorld::Class::get(mPtr).getNpcStats (mPtr);
|
||||
if (npcStats.getSkill (skillId).getBase () <= pcStats.getSkill (skillId).getBase ())
|
||||
{
|
||||
mWindowManager.messageBox ("#{sServiceTrainingWords}", std::vector<std::string>());
|
||||
return;
|
||||
}
|
||||
|
||||
// increase skill
|
||||
MWWorld::LiveCellRef<ESM::NPC> *playerRef = player.get<ESM::NPC>();
|
||||
const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().classes.find (
|
||||
playerRef->base->mClass);
|
||||
pcStats.increaseSkill (skillId, *class_, true);
|
||||
|
||||
// remove gold
|
||||
mWindowManager.getTradeWindow()->addOrRemoveGold(-price);
|
||||
|
||||
// go back to game mode
|
||||
mWindowManager.removeGuiMode (GM_Training);
|
||||
mWindowManager.removeGuiMode (GM_Dialogue);
|
||||
|
||||
// advance time
|
||||
MWBase::Environment::get().getWorld ()->advanceTime (2);
|
||||
|
||||
MWBase::Environment::get().getWorld ()->getFader()->fadeOut(0.25);
|
||||
mFadeTimeRemaining = 0.5;
|
||||
}
|
||||
|
||||
void TrainingWindow::onFrame(float dt)
|
||||
{
|
||||
if (mFadeTimeRemaining <= 0)
|
||||
return;
|
||||
|
||||
mFadeTimeRemaining -= dt;
|
||||
|
||||
if (mFadeTimeRemaining <= 0)
|
||||
MWBase::Environment::get().getWorld ()->getFader()->fadeIn(0.25);
|
||||
}
|
||||
}
|
36
apps/openmw/mwgui/trainingwindow.hpp
Normal file
36
apps/openmw/mwgui/trainingwindow.hpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef MWGUI_TRAININGWINDOW_H
|
||||
#define MWGUI_TRAININGWINDOW_H
|
||||
|
||||
#include "window_base.hpp"
|
||||
#include "referenceinterface.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
class TrainingWindow : public WindowBase, public ReferenceInterface
|
||||
{
|
||||
public:
|
||||
TrainingWindow(MWBase::WindowManager& parWindowManager);
|
||||
|
||||
virtual void open();
|
||||
|
||||
void startTraining(MWWorld::Ptr actor);
|
||||
|
||||
void onFrame(float dt);
|
||||
|
||||
protected:
|
||||
virtual void onReferenceUnavailable ();
|
||||
|
||||
void onCancelButtonClicked (MyGUI::Widget* sender);
|
||||
void onTrainingSelected(MyGUI::Widget* sender);
|
||||
|
||||
MyGUI::Widget* mTrainingOptions;
|
||||
MyGUI::Button* mCancelButton;
|
||||
MyGUI::TextBox* mPlayerGold;
|
||||
|
||||
float mFadeTimeRemaining;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
187
apps/openmw/mwgui/travelwindow.cpp
Normal file
187
apps/openmw/mwgui/travelwindow.cpp
Normal file
|
@ -0,0 +1,187 @@
|
|||
#include "travelwindow.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <libs/openengine/ogre/fader.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/manualref.hpp"
|
||||
|
||||
#include "../mwmechanics/spells.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
#include "inventorywindow.hpp"
|
||||
#include "tradewindow.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
const int TravelWindow::sLineHeight = 18;
|
||||
|
||||
TravelWindow::TravelWindow(MWBase::WindowManager& parWindowManager) :
|
||||
WindowBase("openmw_travel_window.layout", parWindowManager)
|
||||
, mCurrentY(0)
|
||||
, mLastPos(0)
|
||||
{
|
||||
setCoord(0, 0, 450, 300);
|
||||
|
||||
getWidget(mCancelButton, "CancelButton");
|
||||
getWidget(mPlayerGold, "PlayerGold");
|
||||
getWidget(mSelect, "Select");
|
||||
getWidget(mDestinations, "Travel");
|
||||
getWidget(mDestinationsView, "DestinationsView");
|
||||
|
||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TravelWindow::onCancelButtonClicked);
|
||||
|
||||
mDestinations->setCoord(450/2-mDestinations->getTextSize().width/2,
|
||||
mDestinations->getTop(),
|
||||
mDestinations->getTextSize().width,
|
||||
mDestinations->getHeight());
|
||||
mSelect->setCoord(8,
|
||||
mSelect->getTop(),
|
||||
mSelect->getTextSize().width,
|
||||
mSelect->getHeight());
|
||||
}
|
||||
|
||||
void TravelWindow::addDestination(const std::string& travelId,ESM::Position pos,bool interior)
|
||||
{
|
||||
int price = 0;
|
||||
|
||||
if(interior)
|
||||
{
|
||||
price = MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fMagesGuildTravel")->getFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
ESM::Position PlayerPos = player.getRefData().getPosition();
|
||||
float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) );
|
||||
price = d/MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fTravelMult")->getFloat();
|
||||
}
|
||||
|
||||
MyGUI::Button* toAdd = mDestinationsView->createWidget<MyGUI::Button>((price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default);
|
||||
mCurrentY += sLineHeight;
|
||||
/// \todo price adjustment depending on merchantile skill
|
||||
if(interior)
|
||||
toAdd->setUserString("interior","y");
|
||||
else
|
||||
toAdd->setUserString("interior","n");
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << price;
|
||||
toAdd->setUserString("price",oss.str());
|
||||
|
||||
toAdd->setCaptionWithReplacing(travelId+" - "+boost::lexical_cast<std::string>(price)+"#{sgp}");
|
||||
toAdd->setSize(toAdd->getTextSize().width,sLineHeight);
|
||||
toAdd->eventMouseWheel += MyGUI::newDelegate(this, &TravelWindow::onMouseWheel);
|
||||
toAdd->setUserString("Destination", travelId);
|
||||
toAdd->setUserData(pos);
|
||||
toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &TravelWindow::onTravelButtonClick);
|
||||
mDestinationsWidgetMap.insert(std::make_pair (toAdd, travelId));
|
||||
}
|
||||
|
||||
void TravelWindow::clearDestinations()
|
||||
{
|
||||
mDestinationsView->setViewOffset(MyGUI::IntPoint(0,0));
|
||||
mCurrentY = 0;
|
||||
while (mDestinationsView->getChildCount())
|
||||
MyGUI::Gui::getInstance().destroyWidget(mDestinationsView->getChildAt(0));
|
||||
mDestinationsWidgetMap.clear();
|
||||
}
|
||||
|
||||
void TravelWindow::startTravel(const MWWorld::Ptr& actor)
|
||||
{
|
||||
center();
|
||||
mPtr = actor;
|
||||
clearDestinations();
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
for(unsigned int i = 0;i<mPtr.get<ESM::NPC>()->base->mTransport.size();i++)
|
||||
{
|
||||
std::string cellname = mPtr.get<ESM::NPC>()->base->mTransport[i].mCellName;
|
||||
bool interior = true;
|
||||
int x,y;
|
||||
MWBase::Environment::get().getWorld()->positionToIndex(mPtr.get<ESM::NPC>()->base->mTransport[i].mPos.pos[0],
|
||||
mPtr.get<ESM::NPC>()->base->mTransport[i].mPos.pos[1],x,y);
|
||||
if(cellname == "") {cellname = MWBase::Environment::get().getWorld()->getExterior(x,y)->cell->mName; interior= false;}
|
||||
addDestination(cellname,mPtr.get<ESM::NPC>()->base->mTransport[i].mPos,interior);
|
||||
}
|
||||
|
||||
updateLabels();
|
||||
mDestinationsView->setCanvasSize (MyGUI::IntSize(mDestinationsView->getWidth(), std::max(mDestinationsView->getHeight(), mCurrentY)));
|
||||
}
|
||||
|
||||
void TravelWindow::onTravelButtonClick(MyGUI::Widget* _sender)
|
||||
{
|
||||
std::istringstream iss(_sender->getUserString("price"));
|
||||
int price;
|
||||
iss >> price;
|
||||
|
||||
if (mWindowManager.getInventoryWindow()->getPlayerGold()<price)
|
||||
return;
|
||||
|
||||
MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1);
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
ESM::Position pos = *_sender->getUserData<ESM::Position>();
|
||||
std::string cellname = _sender->getUserString("Destination");
|
||||
int x,y;
|
||||
bool interior = _sender->getUserString("interior") == "y";
|
||||
MWBase::Environment::get().getWorld()->positionToIndex(pos.pos[0],pos.pos[1],x,y);
|
||||
MWWorld::CellStore* cell;
|
||||
if(interior) cell = MWBase::Environment::get().getWorld()->getInterior(cellname);
|
||||
else
|
||||
{
|
||||
cell = MWBase::Environment::get().getWorld()->getExterior(x,y);
|
||||
ESM::Position PlayerPos = player.getRefData().getPosition();
|
||||
float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) );
|
||||
int time = int(d /MWBase::Environment::get().getWorld()->getStore().gameSettings.find("fTravelTimeMult")->getFloat());
|
||||
for(int i = 0;i < time;i++)
|
||||
{
|
||||
MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats ();
|
||||
}
|
||||
MWBase::Environment::get().getWorld()->advanceTime(time);
|
||||
}
|
||||
MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]);
|
||||
mWindowManager.removeGuiMode(GM_Travel);
|
||||
mWindowManager.removeGuiMode(GM_Dialogue);
|
||||
MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0);
|
||||
MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(1);
|
||||
}
|
||||
|
||||
void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
mWindowManager.removeGuiMode(GM_Travel);
|
||||
}
|
||||
|
||||
void TravelWindow::updateLabels()
|
||||
{
|
||||
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(mWindowManager.getInventoryWindow()->getPlayerGold()));
|
||||
mPlayerGold->setCoord(8,
|
||||
mPlayerGold->getTop(),
|
||||
mPlayerGold->getTextSize().width,
|
||||
mPlayerGold->getHeight());
|
||||
}
|
||||
|
||||
void TravelWindow::onReferenceUnavailable()
|
||||
{
|
||||
mWindowManager.removeGuiMode(GM_Travel);
|
||||
mWindowManager.removeGuiMode(GM_Dialogue);
|
||||
}
|
||||
|
||||
void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
||||
{
|
||||
if (mDestinationsView->getViewOffset().top + _rel*0.3 > 0)
|
||||
mDestinationsView->setViewOffset(MyGUI::IntPoint(0, 0));
|
||||
else
|
||||
mDestinationsView->setViewOffset(MyGUI::IntPoint(0, mDestinationsView->getViewOffset().top + _rel*0.3));
|
||||
}
|
||||
}
|
||||
|
55
apps/openmw/mwgui/travelwindow.hpp
Normal file
55
apps/openmw/mwgui/travelwindow.hpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
#ifndef MWGUI_TravelWINDOW_H
|
||||
#define MWGUI_TravelWINDOW_H
|
||||
|
||||
#include "container.hpp"
|
||||
#include "window_base.hpp"
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace MyGUI
|
||||
{
|
||||
class Gui;
|
||||
class Widget;
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class WindowManager;
|
||||
}
|
||||
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class TravelWindow : public ReferenceInterface, public WindowBase
|
||||
{
|
||||
public:
|
||||
TravelWindow(MWBase::WindowManager& parWindowManager);
|
||||
|
||||
void startTravel(const MWWorld::Ptr& actor);
|
||||
|
||||
protected:
|
||||
MyGUI::Button* mCancelButton;
|
||||
MyGUI::TextBox* mPlayerGold;
|
||||
MyGUI::TextBox* mDestinations;
|
||||
MyGUI::TextBox* mSelect;
|
||||
|
||||
MyGUI::ScrollView* mDestinationsView;
|
||||
|
||||
std::map<MyGUI::Widget*, std::string> mDestinationsWidgetMap;
|
||||
|
||||
void onCancelButtonClicked(MyGUI::Widget* _sender);
|
||||
void onTravelButtonClick(MyGUI::Widget* _sender);
|
||||
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||
void addDestination(const std::string& destinationID,ESM::Position pos,bool interior);
|
||||
void clearDestinations();
|
||||
int mLastPos,mCurrentY;
|
||||
|
||||
static const int sLineHeight;
|
||||
|
||||
void updateLabels();
|
||||
|
||||
virtual void onReferenceUnavailable();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -122,7 +122,7 @@ namespace MWGui
|
|||
if (hour >= 13) hour -= 12;
|
||||
|
||||
std::string dateTimeText =
|
||||
boost::lexical_cast<std::string>(MWBase::Environment::get().getWorld ()->getDay ()+1) + " "
|
||||
boost::lexical_cast<std::string>(MWBase::Environment::get().getWorld ()->getDay ()) + " "
|
||||
+ month + " (#{sDay} " + boost::lexical_cast<std::string>(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay ()+1)
|
||||
+ ") " + boost::lexical_cast<std::string>(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
|
||||
|
||||
|
|
|
@ -362,6 +362,7 @@ SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects)
|
|||
params.mMagnMin = it->mMagnMin;
|
||||
params.mMagnMax = it->mMagnMax;
|
||||
params.mRange = it->mRange;
|
||||
params.mArea = it->mArea;
|
||||
result.push_back(params);
|
||||
}
|
||||
return result;
|
||||
|
@ -385,343 +386,82 @@ void MWSpellEffect::setSpellEffect(const SpellEffectParams& params)
|
|||
|
||||
void MWSpellEffect::updateWidgets()
|
||||
{
|
||||
if (!mWindowManager)
|
||||
return;
|
||||
|
||||
const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||
const ESM::MagicEffect *magicEffect = store.magicEffects.search(mEffectParams.mEffectID);
|
||||
if (!magicEffect)
|
||||
return;
|
||||
if (mTextWidget)
|
||||
|
||||
assert(magicEffect);
|
||||
assert(mWindowManager);
|
||||
|
||||
std::string pt = mWindowManager->getGameSettingString("spoint", "");
|
||||
std::string pts = mWindowManager->getGameSettingString("spoints", "");
|
||||
std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " ";
|
||||
std::string sec = " " + mWindowManager->getGameSettingString("ssecond", "");
|
||||
std::string secs = " " + mWindowManager->getGameSettingString("sseconds", "");
|
||||
|
||||
std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID);
|
||||
std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, "");
|
||||
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||
{
|
||||
std::string pt = mWindowManager->getGameSettingString("spoint", "");
|
||||
std::string pts = mWindowManager->getGameSettingString("spoints", "");
|
||||
std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " ";
|
||||
std::string sec = " " + mWindowManager->getGameSettingString("ssecond", "");
|
||||
std::string secs = " " + mWindowManager->getGameSettingString("sseconds", "");
|
||||
|
||||
std::string effectIDStr = effectIDToString(mEffectParams.mEffectID);
|
||||
std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, "");
|
||||
if (effectInvolvesSkill(effectIDStr) && mEffectParams.mSkill >= 0 && mEffectParams.mSkill < ESM::Skill::Length)
|
||||
{
|
||||
spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], "");
|
||||
}
|
||||
if (effectInvolvesAttribute(effectIDStr) && mEffectParams.mAttribute >= 0 && mEffectParams.mAttribute < 8)
|
||||
{
|
||||
static const char *attributes[8] = {
|
||||
"sAttributeStrength",
|
||||
"sAttributeIntelligence",
|
||||
"sAttributeWillpower",
|
||||
"sAttributeAgility",
|
||||
"sAttributeSpeed",
|
||||
"sAttributeEndurance",
|
||||
"sAttributePersonality",
|
||||
"sAttributeLuck"
|
||||
};
|
||||
spellLine += " " + mWindowManager->getGameSettingString(attributes[mEffectParams.mAttribute], "");
|
||||
}
|
||||
|
||||
if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && effectHasMagnitude(effectIDStr))
|
||||
{
|
||||
if (mEffectParams.mMagnMin == mEffectParams.mMagnMax)
|
||||
spellLine += " " + boost::lexical_cast<std::string>(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts);
|
||||
else
|
||||
{
|
||||
spellLine += " " + boost::lexical_cast<std::string>(mEffectParams.mMagnMin) + to + boost::lexical_cast<std::string>(mEffectParams.mMagnMax) + " " + pts;
|
||||
}
|
||||
}
|
||||
|
||||
// constant effects have no duration and no target
|
||||
if (!mEffectParams.mIsConstant)
|
||||
{
|
||||
if (mEffectParams.mDuration >= 0 && effectHasDuration(effectIDStr))
|
||||
{
|
||||
spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast<std::string>(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs);
|
||||
}
|
||||
|
||||
// potions have no target
|
||||
if (!mEffectParams.mNoTarget)
|
||||
{
|
||||
std::string on = mWindowManager->getGameSettingString("sonword", "");
|
||||
if (mEffectParams.mRange == ESM::RT_Self)
|
||||
spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", "");
|
||||
else if (mEffectParams.mRange == ESM::RT_Touch)
|
||||
spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", "");
|
||||
else if (mEffectParams.mRange == ESM::RT_Target)
|
||||
spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", "");
|
||||
}
|
||||
}
|
||||
|
||||
static_cast<MyGUI::TextBox*>(mTextWidget)->setCaption(spellLine);
|
||||
mRequestedWidth = mTextWidget->getTextSize().width + 24;
|
||||
spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], "");
|
||||
}
|
||||
if (mImageWidget)
|
||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
||||
{
|
||||
std::string path = std::string("icons\\") + magicEffect->mIcon;
|
||||
fixTexturePath(path);
|
||||
mImageWidget->setImageTexture(path);
|
||||
static const char *attributes[8] = {
|
||||
"sAttributeStrength",
|
||||
"sAttributeIntelligence",
|
||||
"sAttributeWillpower",
|
||||
"sAttributeAgility",
|
||||
"sAttributeSpeed",
|
||||
"sAttributeEndurance",
|
||||
"sAttributePersonality",
|
||||
"sAttributeLuck"
|
||||
};
|
||||
spellLine += " " + mWindowManager->getGameSettingString(attributes[mEffectParams.mAttribute], "");
|
||||
}
|
||||
}
|
||||
|
||||
std::string MWSpellEffect::effectIDToString(const short effectID)
|
||||
{
|
||||
// Map effect ID to GMST name
|
||||
// http://www.uesp.net/morrow/hints/mweffects.shtml
|
||||
std::map<short, std::string> names;
|
||||
names[85] ="sEffectAbsorbAttribute";
|
||||
names[88] ="sEffectAbsorbFatigue";
|
||||
names[86] ="sEffectAbsorbHealth";
|
||||
names[87] ="sEffectAbsorbSpellPoints";
|
||||
names[89] ="sEffectAbsorbSkill";
|
||||
names[63] ="sEffectAlmsiviIntervention";
|
||||
names[47] ="sEffectBlind";
|
||||
names[123] ="sEffectBoundBattleAxe";
|
||||
names[129] ="sEffectBoundBoots";
|
||||
names[127] ="sEffectBoundCuirass";
|
||||
names[120] ="sEffectBoundDagger";
|
||||
names[131] ="sEffectBoundGloves";
|
||||
names[128] ="sEffectBoundHelm";
|
||||
names[125] ="sEffectBoundLongbow";
|
||||
names[121] ="sEffectBoundLongsword";
|
||||
names[122] ="sEffectBoundMace";
|
||||
names[130] ="sEffectBoundShield";
|
||||
names[124] ="sEffectBoundSpear";
|
||||
names[7] ="sEffectBurden";
|
||||
names[50] ="sEffectCalmCreature";
|
||||
names[49] ="sEffectCalmHumanoid";
|
||||
names[40] ="sEffectChameleon";
|
||||
names[44] ="sEffectCharm";
|
||||
names[118] ="sEffectCommandCreatures";
|
||||
names[119] ="sEffectCommandHumanoids";
|
||||
names[132] ="sEffectCorpus"; // NB this typo. (bethesda made it)
|
||||
names[70] ="sEffectCureBlightDisease";
|
||||
names[69] ="sEffectCureCommonDisease";
|
||||
names[71] ="sEffectCureCorprusDisease";
|
||||
names[73] ="sEffectCureParalyzation";
|
||||
names[72] ="sEffectCurePoison";
|
||||
names[22] ="sEffectDamageAttribute";
|
||||
names[25] ="sEffectDamageFatigue";
|
||||
names[23] ="sEffectDamageHealth";
|
||||
names[24] ="sEffectDamageMagicka";
|
||||
names[26] ="sEffectDamageSkill";
|
||||
names[54] ="sEffectDemoralizeCreature";
|
||||
names[53] ="sEffectDemoralizeHumanoid";
|
||||
names[64] ="sEffectDetectAnimal";
|
||||
names[65] ="sEffectDetectEnchantment";
|
||||
names[66] ="sEffectDetectKey";
|
||||
names[38] ="sEffectDisintegrateArmor";
|
||||
names[37] ="sEffectDisintegrateWeapon";
|
||||
names[57] ="sEffectDispel";
|
||||
names[62] ="sEffectDivineIntervention";
|
||||
names[17] ="sEffectDrainAttribute";
|
||||
names[20] ="sEffectDrainFatigue";
|
||||
names[18] ="sEffectDrainHealth";
|
||||
names[19] ="sEffectDrainSpellpoints";
|
||||
names[21] ="sEffectDrainSkill";
|
||||
names[8] ="sEffectFeather";
|
||||
names[14] ="sEffectFireDamage";
|
||||
names[4] ="sEffectFireShield";
|
||||
names[117] ="sEffectFortifyAttackBonus";
|
||||
names[79] ="sEffectFortifyAttribute";
|
||||
names[82] ="sEffectFortifyFatigue";
|
||||
names[80] ="sEffectFortifyHealth";
|
||||
names[81] ="sEffectFortifySpellpoints";
|
||||
names[84] ="sEffectFortifyMagickaMultiplier";
|
||||
names[83] ="sEffectFortifySkill";
|
||||
names[52] ="sEffectFrenzyCreature";
|
||||
names[51] ="sEffectFrenzyHumanoid";
|
||||
names[16] ="sEffectFrostDamage";
|
||||
names[6] ="sEffectFrostShield";
|
||||
names[39] ="sEffectInvisibility";
|
||||
names[9] ="sEffectJump";
|
||||
names[10] ="sEffectLevitate";
|
||||
names[41] ="sEffectLight";
|
||||
names[5] ="sEffectLightningShield";
|
||||
names[12] ="sEffectLock";
|
||||
names[60] ="sEffectMark";
|
||||
names[43] ="sEffectNightEye";
|
||||
names[13] ="sEffectOpen";
|
||||
names[45] ="sEffectParalyze";
|
||||
names[27] ="sEffectPoison";
|
||||
names[56] ="sEffectRallyCreature";
|
||||
names[55] ="sEffectRallyHumanoid";
|
||||
names[61] ="sEffectRecall";
|
||||
names[68] ="sEffectReflect";
|
||||
names[100] ="sEffectRemoveCurse";
|
||||
names[95] ="sEffectResistBlightDisease";
|
||||
names[94] ="sEffectResistCommonDisease";
|
||||
names[96] ="sEffectResistCorprusDisease";
|
||||
names[90] ="sEffectResistFire";
|
||||
names[91] ="sEffectResistFrost";
|
||||
names[93] ="sEffectResistMagicka";
|
||||
names[98] ="sEffectResistNormalWeapons";
|
||||
names[99] ="sEffectResistParalysis";
|
||||
names[97] ="sEffectResistPoison";
|
||||
names[92] ="sEffectResistShock";
|
||||
names[74] ="sEffectRestoreAttribute";
|
||||
names[77] ="sEffectRestoreFatigue";
|
||||
names[75] ="sEffectRestoreHealth";
|
||||
names[76] ="sEffectRestoreSpellPoints";
|
||||
names[78] ="sEffectRestoreSkill";
|
||||
names[42] ="sEffectSanctuary";
|
||||
names[3] ="sEffectShield";
|
||||
names[15] ="sEffectShockDamage";
|
||||
names[46] ="sEffectSilence";
|
||||
names[11] ="sEffectSlowFall";
|
||||
names[58] ="sEffectSoultrap";
|
||||
names[48] ="sEffectSound";
|
||||
names[67] ="sEffectSpellAbsorption";
|
||||
names[136] ="sEffectStuntedMagicka";
|
||||
names[106] ="sEffectSummonAncestralGhost";
|
||||
names[110] ="sEffectSummonBonelord";
|
||||
names[108] ="sEffectSummonLeastBonewalker";
|
||||
names[134] ="sEffectSummonCenturionSphere";
|
||||
names[103] ="sEffectSummonClannfear";
|
||||
names[104] ="sEffectSummonDaedroth";
|
||||
names[105] ="sEffectSummonDremora";
|
||||
names[114] ="sEffectSummonFlameAtronach";
|
||||
names[115] ="sEffectSummonFrostAtronach";
|
||||
names[113] ="sEffectSummonGoldenSaint";
|
||||
names[109] ="sEffectSummonGreaterBonewalker";
|
||||
names[112] ="sEffectSummonHunger";
|
||||
names[102] ="sEffectSummonScamp";
|
||||
names[107] ="sEffectSummonSkeletalMinion";
|
||||
names[116] ="sEffectSummonStormAtronach";
|
||||
names[111] ="sEffectSummonWingedTwilight";
|
||||
names[135] ="sEffectSunDamage";
|
||||
names[1] ="sEffectSwiftSwim";
|
||||
names[59] ="sEffectTelekinesis";
|
||||
names[101] ="sEffectTurnUndead";
|
||||
names[133] ="sEffectVampirism";
|
||||
names[0] ="sEffectWaterBreathing";
|
||||
names[2] ="sEffectWaterWalking";
|
||||
names[33] ="sEffectWeaknesstoBlightDisease";
|
||||
names[32] ="sEffectWeaknesstoCommonDisease";
|
||||
names[34] ="sEffectWeaknesstoCorprusDisease";
|
||||
names[28] ="sEffectWeaknesstoFire";
|
||||
names[29] ="sEffectWeaknesstoFrost";
|
||||
names[31] ="sEffectWeaknesstoMagicka";
|
||||
names[36] ="sEffectWeaknesstoNormalWeapons";
|
||||
names[35] ="sEffectWeaknesstoPoison";
|
||||
names[30] ="sEffectWeaknesstoShock";
|
||||
if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
|
||||
{
|
||||
if (mEffectParams.mMagnMin == mEffectParams.mMagnMax)
|
||||
spellLine += " " + boost::lexical_cast<std::string>(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts);
|
||||
else
|
||||
{
|
||||
spellLine += " " + boost::lexical_cast<std::string>(mEffectParams.mMagnMin) + to + boost::lexical_cast<std::string>(mEffectParams.mMagnMax) + " " + pts;
|
||||
}
|
||||
}
|
||||
|
||||
// bloodmoon
|
||||
names[138] ="sEffectSummonCreature01";
|
||||
names[139] ="sEffectSummonCreature02";
|
||||
names[140] ="sEffectSummonCreature03";
|
||||
names[141] ="sEffectSummonCreature04";
|
||||
names[142] ="sEffectSummonCreature05";
|
||||
// constant effects have no duration and no target
|
||||
if (!mEffectParams.mIsConstant)
|
||||
{
|
||||
if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
|
||||
{
|
||||
spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast<std::string>(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs);
|
||||
}
|
||||
|
||||
// tribunal
|
||||
names[137] ="sEffectSummonFabricant";
|
||||
if (mEffectParams.mArea > 0)
|
||||
{
|
||||
spellLine += " #{sin} " + boost::lexical_cast<std::string>(mEffectParams.mArea) + " #{sfootarea}";
|
||||
}
|
||||
|
||||
assert(names.find(effectID) != names.end() && "Unimplemented effect type");
|
||||
// potions have no target
|
||||
if (!mEffectParams.mNoTarget)
|
||||
{
|
||||
std::string on = mWindowManager->getGameSettingString("sonword", "");
|
||||
if (mEffectParams.mRange == ESM::RT_Self)
|
||||
spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", "");
|
||||
else if (mEffectParams.mRange == ESM::RT_Touch)
|
||||
spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", "");
|
||||
else if (mEffectParams.mRange == ESM::RT_Target)
|
||||
spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", "");
|
||||
}
|
||||
}
|
||||
|
||||
return names[effectID];
|
||||
}
|
||||
static_cast<MyGUI::TextBox*>(mTextWidget)->setCaptionWithReplacing(spellLine);
|
||||
mRequestedWidth = mTextWidget->getTextSize().width + 24;
|
||||
|
||||
bool MWSpellEffect::effectHasDuration(const std::string& effect)
|
||||
{
|
||||
// lists effects that have no duration (e.g. open lock)
|
||||
std::vector<std::string> effectsWithoutDuration;
|
||||
effectsWithoutDuration.push_back("sEffectOpen");
|
||||
effectsWithoutDuration.push_back("sEffectLock");
|
||||
effectsWithoutDuration.push_back("sEffectDispel");
|
||||
effectsWithoutDuration.push_back("sEffectSunDamage");
|
||||
effectsWithoutDuration.push_back("sEffectCorpus");
|
||||
effectsWithoutDuration.push_back("sEffectVampirism");
|
||||
effectsWithoutDuration.push_back("sEffectMark");
|
||||
effectsWithoutDuration.push_back("sEffectRecall");
|
||||
effectsWithoutDuration.push_back("sEffectDivineIntervention");
|
||||
effectsWithoutDuration.push_back("sEffectAlmsiviIntervention");
|
||||
effectsWithoutDuration.push_back("sEffectCureCommonDisease");
|
||||
effectsWithoutDuration.push_back("sEffectCureBlightDisease");
|
||||
effectsWithoutDuration.push_back("sEffectCureCorprusDisease");
|
||||
effectsWithoutDuration.push_back("sEffectCurePoison");
|
||||
effectsWithoutDuration.push_back("sEffectCureParalyzation");
|
||||
effectsWithoutDuration.push_back("sEffectRemoveCurse");
|
||||
effectsWithoutDuration.push_back("sEffectRestoreAttribute");
|
||||
|
||||
return (std::find(effectsWithoutDuration.begin(), effectsWithoutDuration.end(), effect) == effectsWithoutDuration.end());
|
||||
}
|
||||
|
||||
bool MWSpellEffect::effectHasMagnitude(const std::string& effect)
|
||||
{
|
||||
// lists effects that have no magnitude (e.g. invisiblity)
|
||||
std::vector<std::string> effectsWithoutMagnitude;
|
||||
effectsWithoutMagnitude.push_back("sEffectInvisibility");
|
||||
effectsWithoutMagnitude.push_back("sEffectStuntedMagicka");
|
||||
effectsWithoutMagnitude.push_back("sEffectParalyze");
|
||||
effectsWithoutMagnitude.push_back("sEffectSoultrap");
|
||||
effectsWithoutMagnitude.push_back("sEffectSilence");
|
||||
effectsWithoutMagnitude.push_back("sEffectParalyze");
|
||||
effectsWithoutMagnitude.push_back("sEffectInvisibility");
|
||||
effectsWithoutMagnitude.push_back("sEffectWaterWalking");
|
||||
effectsWithoutMagnitude.push_back("sEffectWaterBreathing");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonScamp");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonClannfear");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonDaedroth");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonDremora");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonAncestralGhost");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonSkeletalMinion");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonBonewalker");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonGreaterBonewalker");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonBonelord");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonWingedTwilight");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonHunger");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonGoldenSaint");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonFlameAtronach");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonFrostAtronach");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonStormAtronach");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonCenturionSphere");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundDagger");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundLongsword");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundMace");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundBattleAxe");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundSpear");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundLongbow");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundCuirass");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundHelm");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundBoots");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundShield");
|
||||
effectsWithoutMagnitude.push_back("sEffectBoundGloves");
|
||||
effectsWithoutMagnitude.push_back("sEffectStuntedMagicka");
|
||||
effectsWithoutMagnitude.push_back("sEffectMark");
|
||||
effectsWithoutMagnitude.push_back("sEffectRecall");
|
||||
effectsWithoutMagnitude.push_back("sEffectDivineIntervention");
|
||||
effectsWithoutMagnitude.push_back("sEffectAlmsiviIntervention");
|
||||
effectsWithoutMagnitude.push_back("sEffectCureCommonDisease");
|
||||
effectsWithoutMagnitude.push_back("sEffectCureBlightDisease");
|
||||
effectsWithoutMagnitude.push_back("sEffectCureCorprusDisease");
|
||||
effectsWithoutMagnitude.push_back("sEffectCurePoison");
|
||||
effectsWithoutMagnitude.push_back("sEffectCureParalyzation");
|
||||
effectsWithoutMagnitude.push_back("sEffectRemoveCurse");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonCreature01");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonCreature02");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonCreature03");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonCreature04");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonCreature05");
|
||||
effectsWithoutMagnitude.push_back("sEffectSummonFabricant");
|
||||
|
||||
return (std::find(effectsWithoutMagnitude.begin(), effectsWithoutMagnitude.end(), effect) == effectsWithoutMagnitude.end());
|
||||
}
|
||||
|
||||
bool MWSpellEffect::effectInvolvesAttribute (const std::string& effect)
|
||||
{
|
||||
return (effect == "sEffectRestoreAttribute"
|
||||
|| effect == "sEffectAbsorbAttribute"
|
||||
|| effect == "sEffectDrainAttribute"
|
||||
|| effect == "sEffectFortifyAttribute"
|
||||
|| effect == "sEffectDamageAttribute");
|
||||
}
|
||||
|
||||
bool MWSpellEffect::effectInvolvesSkill (const std::string& effect)
|
||||
{
|
||||
return (effect == "sEffectRestoreSkill"
|
||||
|| effect == "sEffectAbsorbSkill"
|
||||
|| effect == "sEffectDrainSkill"
|
||||
|| effect == "sEffectFortifySkill"
|
||||
|| effect == "sEffectDamageSkill");
|
||||
std::string path = std::string("icons\\") + magicEffect->mIcon;
|
||||
fixTexturePath(path);
|
||||
mImageWidget->setImageTexture(path);
|
||||
}
|
||||
|
||||
MWSpellEffect::~MWSpellEffect()
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace MWGui
|
|||
, mRange(-1)
|
||||
, mDuration(-1)
|
||||
, mSkill(-1)
|
||||
, mArea(0)
|
||||
, mAttribute(-1)
|
||||
, mEffectID(-1)
|
||||
, mNoTarget(false)
|
||||
|
@ -51,6 +52,9 @@ namespace MWGui
|
|||
// value of -1 here means the value is unavailable
|
||||
int mMagnMin, mMagnMax, mRange, mDuration;
|
||||
|
||||
// value of 0 -> no area effect
|
||||
int mArea;
|
||||
|
||||
bool operator==(const SpellEffectParams& other) const
|
||||
{
|
||||
if (mEffectID != other.mEffectID)
|
||||
|
@ -66,7 +70,7 @@ namespace MWGui
|
|||
|| mEffectID == 21 // drain skill
|
||||
|| mEffectID == 83 // fortify skill
|
||||
|| mEffectID == 26); // damage skill
|
||||
return ((other.mSkill == mSkill) || !involvesSkill) && ((other.mAttribute == mAttribute) && !involvesAttribute);
|
||||
return ((other.mSkill == mSkill) || !involvesSkill) && ((other.mAttribute == mAttribute) && !involvesAttribute) && (other.mArea == mArea);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -249,12 +253,6 @@ namespace MWGui
|
|||
void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; }
|
||||
void setSpellEffect(const SpellEffectParams& params);
|
||||
|
||||
std::string effectIDToString(const short effectID);
|
||||
bool effectHasMagnitude (const std::string& effect);
|
||||
bool effectHasDuration (const std::string& effect);
|
||||
bool effectInvolvesAttribute (const std::string& effect);
|
||||
bool effectInvolvesSkill (const std::string& effect);
|
||||
|
||||
int getRequestedWidth() const { return mRequestedWidth; }
|
||||
|
||||
protected:
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "countdialog.hpp"
|
||||
#include "tradewindow.hpp"
|
||||
#include "spellbuyingwindow.hpp"
|
||||
#include "travelwindow.hpp"
|
||||
#include "settingswindow.hpp"
|
||||
#include "confirmationdialog.hpp"
|
||||
#include "alchemywindow.hpp"
|
||||
|
@ -46,6 +47,9 @@
|
|||
#include "loadingscreen.hpp"
|
||||
#include "levelupdialog.hpp"
|
||||
#include "waitdialog.hpp"
|
||||
#include "spellcreationdialog.hpp"
|
||||
#include "enchantingdialog.hpp"
|
||||
#include "trainingwindow.hpp"
|
||||
|
||||
using namespace MWGui;
|
||||
|
||||
|
@ -67,6 +71,7 @@ WindowManager::WindowManager(
|
|||
, mCountDialog(NULL)
|
||||
, mTradeWindow(NULL)
|
||||
, mSpellBuyingWindow(NULL)
|
||||
, mTravelWindow(NULL)
|
||||
, mSettingsWindow(NULL)
|
||||
, mConfirmationDialog(NULL)
|
||||
, mAlchemyWindow(NULL)
|
||||
|
@ -75,6 +80,9 @@ WindowManager::WindowManager(
|
|||
, mCharGen(NULL)
|
||||
, mLevelupDialog(NULL)
|
||||
, mWaitDialog(NULL)
|
||||
, mSpellCreationDialog(NULL)
|
||||
, mEnchantingDialog(NULL)
|
||||
, mTrainingWindow(NULL)
|
||||
, mPlayerClass()
|
||||
, mPlayerName()
|
||||
, mPlayerRaceId()
|
||||
|
@ -141,6 +149,7 @@ WindowManager::WindowManager(
|
|||
mInventoryWindow = new InventoryWindow(*this,mDragAndDrop);
|
||||
mTradeWindow = new TradeWindow(*this);
|
||||
mSpellBuyingWindow = new SpellBuyingWindow(*this);
|
||||
mTravelWindow = new TravelWindow(*this);
|
||||
mDialogueWindow = new DialogueWindow(*this);
|
||||
mContainerWindow = new ContainerWindow(*this,mDragAndDrop);
|
||||
mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop);
|
||||
|
@ -155,6 +164,9 @@ WindowManager::WindowManager(
|
|||
mQuickKeysMenu = new QuickKeysMenu(*this);
|
||||
mLevelupDialog = new LevelupDialog(*this);
|
||||
mWaitDialog = new WaitDialog(*this);
|
||||
mSpellCreationDialog = new SpellCreationDialog(*this);
|
||||
mEnchantingDialog = new EnchantingDialog(*this);
|
||||
mTrainingWindow = new TrainingWindow(*this);
|
||||
|
||||
mLoadingScreen = new LoadingScreen(mOgre->getScene (), mOgre->getWindow (), *this);
|
||||
mLoadingScreen->onResChange (w,h);
|
||||
|
@ -203,6 +215,7 @@ WindowManager::~WindowManager()
|
|||
delete mScrollWindow;
|
||||
delete mTradeWindow;
|
||||
delete mSpellBuyingWindow;
|
||||
delete mTravelWindow;
|
||||
delete mSettingsWindow;
|
||||
delete mConfirmationDialog;
|
||||
delete mAlchemyWindow;
|
||||
|
@ -210,6 +223,9 @@ WindowManager::~WindowManager()
|
|||
delete mLoadingScreen;
|
||||
delete mLevelupDialog;
|
||||
delete mWaitDialog;
|
||||
delete mSpellCreationDialog;
|
||||
delete mEnchantingDialog;
|
||||
delete mTrainingWindow;
|
||||
|
||||
cleanupGarbage();
|
||||
|
||||
|
@ -253,12 +269,16 @@ void WindowManager::updateVisible()
|
|||
mBookWindow->setVisible(false);
|
||||
mTradeWindow->setVisible(false);
|
||||
mSpellBuyingWindow->setVisible(false);
|
||||
mTravelWindow->setVisible(false);
|
||||
mSettingsWindow->setVisible(false);
|
||||
mAlchemyWindow->setVisible(false);
|
||||
mSpellWindow->setVisible(false);
|
||||
mQuickKeysMenu->setVisible(false);
|
||||
mLevelupDialog->setVisible(false);
|
||||
mWaitDialog->setVisible(false);
|
||||
mSpellCreationDialog->setVisible(false);
|
||||
mEnchantingDialog->setVisible(false);
|
||||
mTrainingWindow->setVisible(false);
|
||||
|
||||
mHud->setVisible(true);
|
||||
|
||||
|
@ -359,6 +379,18 @@ void WindowManager::updateVisible()
|
|||
case GM_SpellBuying:
|
||||
mSpellBuyingWindow->setVisible(true);
|
||||
break;
|
||||
case GM_Travel:
|
||||
mTravelWindow->setVisible(true);
|
||||
break;
|
||||
case GM_SpellCreation:
|
||||
mSpellCreationDialog->setVisible(true);
|
||||
break;
|
||||
case GM_Enchanting:
|
||||
mEnchantingDialog->setVisible(true);
|
||||
break;
|
||||
case GM_Training:
|
||||
mTrainingWindow->setVisible(true);
|
||||
break;
|
||||
case GM_InterMessageBox:
|
||||
break;
|
||||
case GM_Journal:
|
||||
|
@ -558,9 +590,14 @@ void WindowManager::onFrame (float frameDuration)
|
|||
|
||||
mHud->onFrame(frameDuration);
|
||||
|
||||
mTrainingWindow->onFrame (frameDuration);
|
||||
|
||||
mTrainingWindow->checkReferenceAvailable();
|
||||
mDialogueWindow->checkReferenceAvailable();
|
||||
mTradeWindow->checkReferenceAvailable();
|
||||
mSpellBuyingWindow->checkReferenceAvailable();
|
||||
mSpellCreationDialog->checkReferenceAvailable();
|
||||
mEnchantingDialog->checkReferenceAvailable();
|
||||
mContainerWindow->checkReferenceAvailable();
|
||||
mConsole->checkReferenceAvailable();
|
||||
}
|
||||
|
@ -844,6 +881,7 @@ MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; }
|
|||
MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; }
|
||||
MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; }
|
||||
MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; }
|
||||
MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; }
|
||||
MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; }
|
||||
MWGui::Console* WindowManager::getConsole() { return mConsole; }
|
||||
|
||||
|
@ -965,3 +1003,18 @@ void WindowManager::addVisitedLocation(const std::string& name, int x, int y)
|
|||
{
|
||||
mMap->addVisitedLocation (name, x, y);
|
||||
}
|
||||
|
||||
void WindowManager::startSpellMaking(MWWorld::Ptr actor)
|
||||
{
|
||||
mSpellCreationDialog->startSpellMaking (actor);
|
||||
}
|
||||
|
||||
void WindowManager::startEnchanting (MWWorld::Ptr actor)
|
||||
{
|
||||
mEnchantingDialog->startEnchanting (actor);
|
||||
}
|
||||
|
||||
void WindowManager::startTraining(MWWorld::Ptr actor)
|
||||
{
|
||||
mTrainingWindow->startTraining(actor);
|
||||
}
|
||||
|
|
|
@ -64,6 +64,9 @@ namespace MWGui
|
|||
class LoadingScreen;
|
||||
class LevelupDialog;
|
||||
class WaitDialog;
|
||||
class SpellCreationDialog;
|
||||
class EnchantingDialog;
|
||||
class TrainingWindow;
|
||||
|
||||
class WindowManager : public MWBase::WindowManager
|
||||
{
|
||||
|
@ -111,6 +114,7 @@ namespace MWGui
|
|||
virtual MWGui::ConfirmationDialog* getConfirmationDialog();
|
||||
virtual MWGui::TradeWindow* getTradeWindow();
|
||||
virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow();
|
||||
virtual MWGui::TravelWindow* getTravelWindow();
|
||||
virtual MWGui::SpellWindow* getSpellWindow();
|
||||
virtual MWGui::Console* getConsole();
|
||||
|
||||
|
@ -211,6 +215,10 @@ namespace MWGui
|
|||
virtual bool getPlayerSleeping();
|
||||
virtual void wakeUpPlayer();
|
||||
|
||||
virtual void startSpellMaking(MWWorld::Ptr actor);
|
||||
virtual void startEnchanting(MWWorld::Ptr actor);
|
||||
virtual void startTraining(MWWorld::Ptr actor);
|
||||
|
||||
private:
|
||||
OEngine::GUI::MyGUIManager *mGuiManager;
|
||||
HUD *mHud;
|
||||
|
@ -230,6 +238,7 @@ namespace MWGui
|
|||
CountDialog* mCountDialog;
|
||||
TradeWindow* mTradeWindow;
|
||||
SpellBuyingWindow* mSpellBuyingWindow;
|
||||
TravelWindow* mTravelWindow;
|
||||
SettingsWindow* mSettingsWindow;
|
||||
ConfirmationDialog* mConfirmationDialog;
|
||||
AlchemyWindow* mAlchemyWindow;
|
||||
|
@ -238,6 +247,9 @@ namespace MWGui
|
|||
LoadingScreen* mLoadingScreen;
|
||||
LevelupDialog* mLevelupDialog;
|
||||
WaitDialog* mWaitDialog;
|
||||
SpellCreationDialog* mSpellCreationDialog;
|
||||
EnchantingDialog* mEnchantingDialog;
|
||||
TrainingWindow* mTrainingWindow;
|
||||
|
||||
CharacterCreation* mCharGen;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <OIS/OISInputManager.h>
|
||||
#include <OISInputManager.h>
|
||||
|
||||
#include <MyGUI_InputManager.h>
|
||||
#include <MyGUI_RenderManager.h>
|
||||
|
|
|
@ -42,8 +42,8 @@ namespace OIS
|
|||
class InputManager;
|
||||
}
|
||||
|
||||
#include <OIS/OISKeyboard.h>
|
||||
#include <OIS/OISMouse.h>
|
||||
#include <OISKeyboard.h>
|
||||
#include <OISMouse.h>
|
||||
|
||||
#include <extern/oics/ICSChannelListener.h>
|
||||
#include <extern/oics/ICSInputControlSystem.h>
|
||||
|
|
|
@ -24,8 +24,8 @@ namespace MWMechanics
|
|||
{
|
||||
// magic effects
|
||||
adjustMagicEffects (ptr);
|
||||
calculateCreatureStatModifiers (ptr);
|
||||
calculateDynamicStats (ptr);
|
||||
calculateCreatureStatModifiers (ptr);
|
||||
|
||||
// AI
|
||||
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||
|
@ -73,13 +73,17 @@ namespace MWMechanics
|
|||
double magickaFactor =
|
||||
creatureStats.getMagicEffects().get (EffectKey (84)).mMagnitude * 0.1 + 0.5;
|
||||
|
||||
creatureStats.getHealth().setBase(
|
||||
static_cast<int> (0.5 * (strength + endurance)) + creatureStats.getLevelHealthBonus ());
|
||||
DynamicStat<float> health = creatureStats.getHealth();
|
||||
health.setBase (static_cast<int> (0.5 * (strength + endurance)) + creatureStats.getLevelHealthBonus ());
|
||||
creatureStats.setHealth (health);
|
||||
|
||||
creatureStats.getMagicka().setBase(
|
||||
static_cast<int> (intelligence + magickaFactor * intelligence));
|
||||
|
||||
creatureStats.getFatigue().setBase(strength+willpower+agility+endurance);
|
||||
DynamicStat<float> magicka = creatureStats.getMagicka();
|
||||
magicka.setBase (static_cast<int> (intelligence + magickaFactor * intelligence));
|
||||
creatureStats.setMagicka (magicka);
|
||||
|
||||
DynamicStat<float> fatigue = creatureStats.getFatigue();
|
||||
fatigue.setBase (strength+willpower+agility+endurance);
|
||||
creatureStats.setFatigue (fatigue);
|
||||
}
|
||||
|
||||
void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration)
|
||||
|
@ -92,8 +96,10 @@ namespace MWMechanics
|
|||
bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(136)).mMagnitude > 0;
|
||||
|
||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||
stats.getHealth().setCurrent(stats.getHealth ().getCurrent ()
|
||||
+ 0.1 * endurance);
|
||||
|
||||
DynamicStat<float> health = stats.getHealth();
|
||||
health.setCurrent (health.getCurrent() + 0.1 * endurance);
|
||||
stats.setHealth (health);
|
||||
|
||||
const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
|
@ -109,27 +115,29 @@ namespace MWMechanics
|
|||
|
||||
float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
|
||||
x *= fEndFatigueMult * endurance;
|
||||
stats.getFatigue ().setCurrent (stats.getFatigue ().getCurrent () + 3600 * x);
|
||||
|
||||
|
||||
DynamicStat<float> fatigue = stats.getFatigue();
|
||||
fatigue.setCurrent (fatigue.getCurrent() + 3600 * x);
|
||||
stats.setFatigue (fatigue);
|
||||
|
||||
if (!stunted)
|
||||
{
|
||||
float fRestMagicMult = store.gameSettings.find("fRestMagicMult")->getFloat ();
|
||||
stats.getMagicka().setCurrent (stats.getMagicka ().getCurrent ()
|
||||
+ fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified ());
|
||||
|
||||
DynamicStat<float> magicka = stats.getMagicka();
|
||||
magicka.setCurrent (magicka.getCurrent()
|
||||
+ fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified());
|
||||
stats.setMagicka (magicka);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||
|
||||
// attributes
|
||||
for (int i=0; i<5; ++i)
|
||||
for (int i=0; i<8; ++i)
|
||||
{
|
||||
int modifier =
|
||||
creatureStats.getMagicEffects().get (EffectKey (79, i)).mMagnitude;
|
||||
|
@ -141,21 +149,26 @@ namespace MWMechanics
|
|||
|
||||
// dynamic stats
|
||||
MagicEffects effects = creatureStats.getMagicEffects();
|
||||
creatureStats.getHealth().setModifier(
|
||||
effects.get(EffectKey(80)).mMagnitude - effects.get(EffectKey(18)).mMagnitude);
|
||||
|
||||
creatureStats.getMagicka().setModifier(
|
||||
effects.get(EffectKey(81)).mMagnitude - effects.get(EffectKey(19)).mMagnitude);
|
||||
|
||||
creatureStats.getFatigue().setModifier(
|
||||
effects.get(EffectKey(82)).mMagnitude - effects.get(EffectKey(20)).mMagnitude);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
DynamicStat<float> stat = creatureStats.getDynamic (i);
|
||||
|
||||
stat.setModifier (
|
||||
effects.get (EffectKey(80+i)).mMagnitude - effects.get (EffectKey(18+i)).mMagnitude);
|
||||
|
||||
creatureStats.setDynamic (i, stat);
|
||||
}
|
||||
}
|
||||
|
||||
Actors::Actors() : mDuration (0) {}
|
||||
|
||||
void Actors::addActor (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
mActors.insert (ptr);
|
||||
if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead())
|
||||
mActors.insert (ptr);
|
||||
else
|
||||
MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2);
|
||||
}
|
||||
|
||||
void Actors::removeActor (const MWWorld::Ptr& ptr)
|
||||
|
@ -188,13 +201,51 @@ namespace MWMechanics
|
|||
{
|
||||
float totalDuration = mDuration;
|
||||
mDuration = 0;
|
||||
|
||||
std::set<MWWorld::Ptr>::iterator iter (mActors.begin());
|
||||
|
||||
for (std::set<MWWorld::Ptr>::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter)
|
||||
while (iter!=mActors.end())
|
||||
{
|
||||
updateActor (*iter, totalDuration);
|
||||
if (!MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead())
|
||||
{
|
||||
updateActor (*iter, totalDuration);
|
||||
|
||||
if (iter->getTypeName()==typeid (ESM::NPC).name())
|
||||
updateNpc (*iter, totalDuration, paused);
|
||||
if (iter->getTypeName()==typeid (ESM::NPC).name())
|
||||
updateNpc (*iter, totalDuration, paused);
|
||||
}
|
||||
|
||||
if (MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead())
|
||||
{
|
||||
// workaround: always keep player alive for now
|
||||
// \todo remove workaround, once player death can be handled
|
||||
if (iter->getRefData().getHandle()=="player")
|
||||
{
|
||||
MWMechanics::DynamicStat<float> stat (
|
||||
MWWorld::Class::get (*iter).getCreatureStats (*iter).getHealth());
|
||||
|
||||
if (stat.getModified()<1)
|
||||
{
|
||||
stat.setModified (1, 0);
|
||||
MWWorld::Class::get (*iter).getCreatureStats (*iter).setHealth (stat);
|
||||
}
|
||||
|
||||
MWWorld::Class::get (*iter).getCreatureStats (*iter).resurrect();
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
++mDeathCount[MWWorld::Class::get (*iter).getId (*iter)];
|
||||
|
||||
MWBase::Environment::get().getWorld()->playAnimationGroup (*iter, "death1", 0);
|
||||
|
||||
if (MWWorld::Class::get (*iter).isEssential (*iter))
|
||||
MWBase::Environment::get().getWindowManager()->messageBox (
|
||||
"#{sKilledEssential}", std::vector<std::string>());
|
||||
|
||||
mActors.erase (iter++);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,4 +266,14 @@ namespace MWMechanics
|
|||
calculateRestoration (*iter, 3600);
|
||||
}
|
||||
}
|
||||
|
||||
int Actors::countDeaths (const std::string& id) const
|
||||
{
|
||||
std::map<std::string, int>::const_iterator iter = mDeathCount.find (id);
|
||||
|
||||
if (iter!=mDeathCount.end())
|
||||
return iter->second;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue