Merge remote-tracking branch 'upstream/next' into multiple_esm_esp

actorid
Mark Siewert 12 years ago
commit 64c08eada4

@ -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());

@ -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;
}

@ -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 &current);
void profileRenamed(const QString &previous, const QString &current);
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)"));
}
} 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:

@ -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();
}

@ -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

@ -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;
}

@ -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

@ -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);
}

@ -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

@ -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);
}

@ -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 &current);
void profileRenamed(const QString &oldName, const QString &newName);
private slots:
void slotReturnPressed();
void slotIndexChanged(int index);
private:
QString mOldProfile;
QRegExpValidator *mValidator;
};
#endif // PROFILESCOMBOBOX_HPP

@ -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);
}

@ -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)
{
// check if mortar & pestle is available (always needed)
/// \todo check albemic, calcinator, retort (sometimes needed)
if (!mApparatus1->isUserString("ToolTipType"))
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("#{sNotifyMessage45}", std::vector<std::string>());
mWindowManager.messageBox("#{sNotifyMessage37}", 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)
// check if mortar & pestle is available (always needed)
if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle)
{
mWindowManager.messageBox("#{sNotifyMessage6a}", std::vector<std::string>());
mWindowManager.messageBox("#{sNotifyMessage45}", std::vector<std::string>());
return;
}
// make sure a name was entered
std::string name = mNameEdit->getCaption();
boost::algorithm::trim(name);
if (name == "")
// make sure 2 or more ingredients were selected
if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients)
{
mWindowManager.messageBox("#{sNotifyMessage37}", std::vector<std::string>());
mWindowManager.messageBox("#{sNotifyMessage6a}", 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)
{
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;
}
int index = 0;
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())
for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy.beginTools());
iter!=mAlchemy.endTools() && index<static_cast<int> (mApparatus.size()); ++iter, ++index)
{
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));
if (!iter->isEmpty())
{
mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr");
mApparatus.at (index)->setUserData (*iter);
mApparatus.at (index)->setImageTexture (getIconPath (*iter));
}
}
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"))
{
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"))
if (res != -1)
{
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;
if (!ingredient->isUserString("ToolTipType"))
continue;
MyGUI::ImageBox* ingredient = mIngredients[i];
// 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;
}
if (!found)
it = effects.erase(it);
else
++it;
}
drawItems();
// 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)
{
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)
{
const ESM::BirthSign &birth = it->second;
mBirthList->addItem(birth.mName, it->first);
if (boost::iequals(it->first, mCurrentBirthId))
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;

@ -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);
}
}

@ -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);

@ -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);
}
}

@ -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;

@ -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);
}
}

@ -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

@ -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));
}
}

@ -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)
{
spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], "");
}
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
{
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) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
{
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)
if (mEffectParams.mMagnMin == mEffectParams.mMagnMax)
spellLine += " " + boost::lexical_cast<std::string>(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts);
else
{
spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], "");
spellLine += " " + boost::lexical_cast<std::string>(mEffectParams.mMagnMin) + to + boost::lexical_cast<std::string>(mEffectParams.mMagnMax) + " " + pts;
}
if (effectInvolvesAttribute(effectIDStr) && mEffectParams.mAttribute >= 0 && mEffectParams.mAttribute < 8)
}
// constant effects have no duration and no target
if (!mEffectParams.mIsConstant)
{
if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration))
{
static const char *attributes[8] = {
"sAttributeStrength",
"sAttributeIntelligence",
"sAttributeWillpower",
"sAttributeAgility",
"sAttributeSpeed",
"sAttributeEndurance",
"sAttributePersonality",
"sAttributeLuck"
};
spellLine += " " + mWindowManager->getGameSettingString(attributes[mEffectParams.mAttribute], "");
spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast<std::string>(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs);
}
if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && effectHasMagnitude(effectIDStr))
if (mEffectParams.mArea > 0)
{
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;
}
spellLine += " #{sin} " + boost::lexical_cast<std::string>(mEffectParams.mArea) + " #{sfootarea}";
}
// constant effects have no duration and no target
if (!mEffectParams.mIsConstant)
// potions have no target
if (!mEffectParams.mNoTarget)
{
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", "");
}
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;
}
if (mImageWidget)
{
std::string path = std::string("icons\\") + magicEffect->mIcon;
fixTexturePath(path);
mImageWidget->setImageTexture(path);
}
}
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";
// bloodmoon
names[138] ="sEffectSummonCreature01";
names[139] ="sEffectSummonCreature02";
names[140] ="sEffectSummonCreature03";
names[141] ="sEffectSummonCreature04";
names[142] ="sEffectSummonCreature05";
// tribunal
names[137] ="sEffectSummonFabricant";
assert(names.find(effectID) != names.end() && "Unimplemented effect type");
return names[effectID];
}
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");
}
static_cast<MyGUI::TextBox*>(mTextWidget)->setCaptionWithReplacing(spellLine);
mRequestedWidth = mTextWidget->getTextSize().width + 24;
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 ());
creatureStats.getMagicka().setBase(
static_cast<int> (intelligence + magickaFactor * intelligence));
creatureStats.getFatigue().setBase(strength+willpower+agility+endurance);
DynamicStat<float> health = creatureStats.getHealth();
health.setBase (static_cast<int> (0.5 * (strength + endurance)) + creatureStats.getLevelHealthBonus ());
creatureStats.setHealth (health);
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 (iter->getTypeName()==typeid (ESM::NPC).name())
updateNpc (*iter, totalDuration, paused);
if (!MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead())
{
updateActor (*iter, totalDuration);
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…
Cancel
Save