mirror of https://github.com/OpenMW/openmw.git
Merge branch 'master' into videoplayback
Conflicts: apps/openmw/mwrender/renderingmanager.cpppull/16/head
commit
c4facc233e
@ -1,3 +1 @@
|
||||
[submodule "extern/shiny"]
|
||||
path = extern/shiny
|
||||
url = git://github.com/scrawl/shiny.git
|
||||
|
||||
|
@ -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
@ -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
@ -0,0 +1,476 @@
|
||||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#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 ¤t);
|
||||
void profileRenamed(const QString &oldName, const QString &newName);
|
||||
|
||||
private slots:
|
||||
void slotReturnPressed();
|
||||
void slotIndexChanged(int index);
|
||||
|
||||
private:
|
||||
QString mOldProfile;
|
||||
QRegExpValidator *mValidator;
|
||||
};
|
||||
|
||||
#endif // PROFILESCOMBOBOX_HPP
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,570 @@
|
||||
|
||||
#include "filter.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/magiceffects.hpp"
|
||||
|
||||
#include "selectwrapper.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string toLower (const std::string& name)
|
||||
{
|
||||
std::string lowerCase;
|
||||
|
||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||
(int(*)(int)) std::tolower);
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
||||
{
|
||||
// actor id
|
||||
if (!info.mActor.empty())
|
||||
if (toLower (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor))
|
||||
return false;
|
||||
|
||||
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
|
||||
|
||||
// NPC race
|
||||
if (!info.mRace.empty())
|
||||
{
|
||||
if (isCreature)
|
||||
return false;
|
||||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>();
|
||||
|
||||
if (toLower (info.mRace)!=toLower (cellRef->mBase->mRace))
|
||||
return false;
|
||||
}
|
||||
|
||||
// NPC class
|
||||
if (!info.mClass.empty())
|
||||
{
|
||||
if (isCreature)
|
||||
return false;
|
||||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *cellRef = mActor.get<ESM::NPC>();
|
||||
|
||||
if (toLower (info.mClass)!=toLower (cellRef->mBase->mClass))
|
||||
return false;
|
||||
}
|
||||
|
||||
// NPC faction
|
||||
if (!info.mNpcFaction.empty())
|
||||
{
|
||||
if (isCreature)
|
||||
return false;
|
||||
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (mActor).getNpcStats (mActor);
|
||||
std::map<std::string, int>::iterator iter = stats.getFactionRanks().find (toLower (info.mNpcFaction));
|
||||
|
||||
if (iter==stats.getFactionRanks().end())
|
||||
return false;
|
||||
|
||||
// check rank
|
||||
if (iter->second < info.mData.mRank)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gender
|
||||
if (!isCreature)
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::NPC>* npc = mActor.get<ESM::NPC>();
|
||||
if (info.mData.mGender==(npc->mBase->mFlags & npc->mBase->Female ? 0 : 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
|
||||
{
|
||||
const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
// check player faction
|
||||
if (!info.mPcFaction.empty())
|
||||
{
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (player).getNpcStats (player);
|
||||
std::map<std::string,int>::iterator iter = stats.getFactionRanks().find (toLower (info.mPcFaction));
|
||||
|
||||
if(iter==stats.getFactionRanks().end())
|
||||
return false;
|
||||
|
||||
// check rank
|
||||
if (iter->second < info.mData.mPCrank)
|
||||
return false;
|
||||
}
|
||||
|
||||
// check cell
|
||||
if (!info.mCell.empty())
|
||||
if (toLower (player.getCell()->mCell->mName) != toLower (info.mCell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const
|
||||
{
|
||||
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator iter (info.mSelects.begin());
|
||||
iter != info.mSelects.end(); ++iter)
|
||||
if (!testSelectStruct (*iter))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const
|
||||
{
|
||||
if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name())
|
||||
return select.isInverted();
|
||||
|
||||
switch (select.getType())
|
||||
{
|
||||
case SelectWrapper::Type_None: return true;
|
||||
case SelectWrapper::Type_Integer: return select.selectCompare (getSelectStructInteger (select));
|
||||
case SelectWrapper::Type_Numeric: return testSelectStructNumeric (select);
|
||||
case SelectWrapper::Type_Boolean: return select.selectCompare (getSelectStructBoolean (select));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) const
|
||||
{
|
||||
switch (select.getFunction())
|
||||
{
|
||||
case SelectWrapper::Function_Global:
|
||||
|
||||
// internally all globals are float :(
|
||||
return select.selectCompare (
|
||||
MWBase::Environment::get().getWorld()->getGlobalVariable (select.getName()).mFloat);
|
||||
|
||||
case SelectWrapper::Function_Local:
|
||||
{
|
||||
std::string scriptName = MWWorld::Class::get (mActor).getScript (mActor);
|
||||
|
||||
if (scriptName.empty())
|
||||
return false; // no script
|
||||
|
||||
const ESM::Script *script =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptName);
|
||||
|
||||
std::string name = select.getName();
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (; i<static_cast<int> (script->mVarNames.size()); ++i)
|
||||
if (script->mVarNames[i]==name)
|
||||
break;
|
||||
|
||||
if (i>=static_cast<int> (script->mVarNames.size()))
|
||||
return false; // script does not have a variable of this name
|
||||
|
||||
const MWScript::Locals& locals = mActor.getRefData().getLocals();
|
||||
|
||||
if (i<script->mData.mNumShorts)
|
||||
return select.selectCompare (static_cast<int> (locals.mShorts[i]));
|
||||
|
||||
i -= script->mData.mNumShorts;
|
||||
|
||||
if (i<script->mData.mNumLongs)
|
||||
return select.selectCompare (locals.mLongs[i]);
|
||||
|
||||
i -= script->mData.mNumShorts;
|
||||
|
||||
return select.selectCompare (locals.mFloats.at (i));
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcHealthPercent:
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
float ratio = MWWorld::Class::get (player).getCreatureStats (player).getHealth().getCurrent() /
|
||||
MWWorld::Class::get (player).getCreatureStats (player).getHealth().getModified();
|
||||
|
||||
return select.selectCompare (ratio);
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcDynamicStat:
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
float value = MWWorld::Class::get (player).getCreatureStats (player).
|
||||
getDynamic (select.getArgument()).getCurrent();
|
||||
|
||||
return select.selectCompare (value);
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_HealthPercent:
|
||||
{
|
||||
float ratio = MWWorld::Class::get (mActor).getCreatureStats (mActor).getHealth().getCurrent() /
|
||||
MWWorld::Class::get (mActor).getCreatureStats (mActor).getHealth().getModified();
|
||||
|
||||
return select.selectCompare (ratio);
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unknown numeric select function");
|
||||
}
|
||||
}
|
||||
|
||||
int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) const
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
switch (select.getFunction())
|
||||
{
|
||||
case SelectWrapper::Function_Journal:
|
||||
|
||||
return MWBase::Environment::get().getJournal()->getJournalIndex (select.getName());
|
||||
|
||||
case SelectWrapper::Function_Item:
|
||||
{
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get (player).getContainerStore (player);
|
||||
|
||||
int sum = 0;
|
||||
|
||||
std::string name = select.getName();
|
||||
|
||||
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
|
||||
if (toLower(iter->getCellRef().mRefID) == name)
|
||||
sum += iter->getRefData().getCount();
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_Dead:
|
||||
|
||||
return MWBase::Environment::get().getMechanicsManager()->countDeaths (select.getName());
|
||||
|
||||
case SelectWrapper::Function_Choice:
|
||||
|
||||
return mChoice;
|
||||
|
||||
case SelectWrapper::Function_AiSetting:
|
||||
|
||||
return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAiSetting (select.getArgument());
|
||||
|
||||
case SelectWrapper::Function_PcAttribute:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).
|
||||
getAttribute (select.getArgument()).getModified();
|
||||
|
||||
case SelectWrapper::Function_PcSkill:
|
||||
|
||||
return static_cast<int> (MWWorld::Class::get (player).
|
||||
getNpcStats (player).getSkill (select.getArgument()).getModified());
|
||||
|
||||
case SelectWrapper::Function_FriendlyHit:
|
||||
{
|
||||
int hits = MWWorld::Class::get (mActor).getCreatureStats (mActor).getFriendlyHits();
|
||||
|
||||
return hits>4 ? 4 : hits;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcLevel:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).getLevel();
|
||||
|
||||
case SelectWrapper::Function_PcGender:
|
||||
|
||||
return player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female ? 0 : 1;
|
||||
|
||||
case SelectWrapper::Function_PcClothingModifier:
|
||||
{
|
||||
MWWorld::InventoryStore& store = MWWorld::Class::get (player).getInventoryStore (player);
|
||||
|
||||
int value = 0;
|
||||
|
||||
for (int i=0; i<=15; ++i) // everything except thigns held in hands and amunition
|
||||
{
|
||||
MWWorld::ContainerStoreIterator slot = store.getSlot (i);
|
||||
|
||||
if (slot!=store.end())
|
||||
value += MWWorld::Class::get (*slot).getValue (*slot);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcCrimeLevel:
|
||||
|
||||
return MWWorld::Class::get (player).getNpcStats (player).getBounty();
|
||||
|
||||
case SelectWrapper::Function_RankRequirement:
|
||||
{
|
||||
if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty())
|
||||
return 0;
|
||||
|
||||
std::string faction =
|
||||
MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first;
|
||||
|
||||
int rank = getFactionRank (player, faction);
|
||||
|
||||
if (rank>=9)
|
||||
return 0; // max rank
|
||||
|
||||
int result = 0;
|
||||
|
||||
if (hasFactionRankSkillRequirements (player, faction, rank+1))
|
||||
result += 1;
|
||||
|
||||
if (hasFactionRankReputationRequirements (player, faction, rank+1))
|
||||
result += 2;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_Level:
|
||||
|
||||
return MWWorld::Class::get (mActor).getCreatureStats (mActor).getLevel();
|
||||
|
||||
case SelectWrapper::Function_PCReputation:
|
||||
|
||||
return MWWorld::Class::get (player).getNpcStats (player).getReputation();
|
||||
|
||||
case SelectWrapper::Function_Weather:
|
||||
|
||||
return MWBase::Environment::get().getWorld()->getCurrentWeather();
|
||||
|
||||
case SelectWrapper::Function_Reputation:
|
||||
|
||||
return MWWorld::Class::get (mActor).getNpcStats (mActor).getReputation();
|
||||
|
||||
case SelectWrapper::Function_FactionRankDiff:
|
||||
{
|
||||
if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty())
|
||||
return 0;
|
||||
|
||||
std::pair<std::string, int> faction =
|
||||
*MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin();
|
||||
|
||||
int rank = getFactionRank (player, faction.first);
|
||||
|
||||
return rank-faction.second;
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_WerewolfKills:
|
||||
|
||||
return MWWorld::Class::get (player).getNpcStats (player).getWerewolfKills();
|
||||
|
||||
case SelectWrapper::Function_RankLow:
|
||||
case SelectWrapper::Function_RankHigh:
|
||||
{
|
||||
bool low = select.getFunction()==SelectWrapper::Function_RankLow;
|
||||
|
||||
if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty())
|
||||
return 0;
|
||||
|
||||
std::string factionId =
|
||||
MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first;
|
||||
|
||||
int value = 0;
|
||||
|
||||
const ESM::Faction& faction =
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find (factionId);
|
||||
|
||||
MWMechanics::NpcStats& playerStats = MWWorld::Class::get (player).getNpcStats (player);
|
||||
|
||||
for (std::vector<ESM::Faction::Reaction>::const_iterator iter (faction.mReactions.begin());
|
||||
iter!=faction.mReactions.end(); ++iter)
|
||||
if (playerStats.getFactionRanks().find (iter->mFaction)!=playerStats.getFactionRanks().end())
|
||||
if (low ? iter->mReaction<value : iter->mReaction>value)
|
||||
value = iter->mReaction;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unknown integer select function");
|
||||
}
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
switch (select.getFunction())
|
||||
{
|
||||
case SelectWrapper::Function_False:
|
||||
|
||||
return false;
|
||||
|
||||
case SelectWrapper::Function_Id:
|
||||
|
||||
return select.getName()==toLower (MWWorld::Class::get (mActor).getId (mActor));
|
||||
|
||||
case SelectWrapper::Function_Faction:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mFaction)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_Class:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mClass)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_Race:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mRace)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_Cell:
|
||||
|
||||
return toLower (mActor.getCell()->mCell->mName)==select.getName();
|
||||
|
||||
case SelectWrapper::Function_SameGender:
|
||||
|
||||
return (player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female)==
|
||||
(mActor.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female);
|
||||
|
||||
case SelectWrapper::Function_SameRace:
|
||||
|
||||
return toLower (mActor.get<ESM::NPC>()->mBase->mRace)!=
|
||||
toLower (player.get<ESM::NPC>()->mBase->mRace);
|
||||
|
||||
case SelectWrapper::Function_SameFaction:
|
||||
|
||||
return MWWorld::Class::get (mActor).getNpcStats (mActor).isSameFaction (
|
||||
MWWorld::Class::get (player).getNpcStats (player));
|
||||
|
||||
case SelectWrapper::Function_PcCommonDisease:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).hasCommonDisease();
|
||||
|
||||
case SelectWrapper::Function_PcBlightDisease:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).hasBlightDisease();
|
||||
|
||||
case SelectWrapper::Function_PcCorprus:
|
||||
|
||||
return MWWorld::Class::get (player).getCreatureStats (player).
|
||||
getMagicEffects().get (132).mMagnitude!=0;
|
||||
|
||||
case SelectWrapper::Function_PcExpelled:
|
||||
{
|
||||
if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty())
|
||||
return false;
|
||||
|
||||
std::string faction =
|
||||
MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first;
|
||||
|
||||
std::set<std::string>& expelled = MWWorld::Class::get (player).getNpcStats (player).getExpelled();
|
||||
|
||||
return expelled.find (faction)!=expelled.end();
|
||||
}
|
||||
|
||||
case SelectWrapper::Function_PcVampire:
|
||||
|
||||
return MWWorld::Class::get (player).getNpcStats (player).isVampire();
|
||||
|
||||
case SelectWrapper::Function_TalkedToPc:
|
||||
|
||||
return mTalkedToPlayer;
|
||||
|
||||
case SelectWrapper::Function_Alarmed:
|
||||
|
||||
return MWWorld::Class::get (mActor).getCreatureStats (mActor).isAlarmed();
|
||||
|
||||
case SelectWrapper::Function_Detected:
|
||||
|
||||
return MWWorld::Class::get (mActor).hasDetected (mActor, player);
|
||||
|
||||
case SelectWrapper::Function_Attacked:
|
||||
|
||||
return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAttacked();
|
||||
|
||||
case SelectWrapper::Function_ShouldAttack:
|
||||
|
||||
return MWWorld::Class::get (mActor).getCreatureStats (mActor).isHostile();
|
||||
|
||||
case SelectWrapper::Function_CreatureTargetted:
|
||||
|
||||
return MWWorld::Class::get (mActor).getCreatureStats (mActor).getCreatureTargetted();
|
||||
|
||||
case SelectWrapper::Function_PCWerewolf:
|
||||
|
||||
return MWWorld::Class::get (player).getNpcStats (player).isWerewolf();
|
||||
|
||||
default:
|
||||
|
||||
throw std::runtime_error ("unknown boolean select function");
|
||||
}
|
||||
}
|
||||
|
||||
int MWDialogue::Filter::getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const
|
||||
{
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (actor).getNpcStats (actor);
|
||||
|
||||
std::map<std::string, int>::const_iterator iter = stats.getFactionRanks().find (factionId);
|
||||
|
||||
if (iter==stats.getFactionRanks().end())
|
||||
return -1;
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::hasFactionRankSkillRequirements (const MWWorld::Ptr& actor,
|
||||
const std::string& factionId, int rank) const
|
||||
{
|
||||
if (rank<0 || rank>=10)
|
||||
throw std::runtime_error ("rank index out of range");
|
||||
|
||||
if (!MWWorld::Class::get (actor).getNpcStats (actor).hasSkillsForRank (factionId, rank))
|
||||
return false;
|
||||
|
||||
const ESM::Faction& faction =
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find (factionId);
|
||||
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get (actor).getCreatureStats (actor);
|
||||
|
||||
return stats.getAttribute (faction.mData.mAttribute1).getBase()>=faction.mData.mRankData[rank].mAttribute1 &&
|
||||
stats.getAttribute (faction.mData.mAttribute2).getBase()>=faction.mData.mRankData[rank].mAttribute2;
|
||||
}
|
||||
|
||||
bool MWDialogue::Filter::hasFactionRankReputationRequirements (const MWWorld::Ptr& actor,
|
||||
const std::string& factionId, int rank) const
|
||||
{
|
||||
if (rank<0 || rank>=10)
|
||||
throw std::runtime_error ("rank index out of range");
|
||||
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (actor).getNpcStats (actor);
|
||||
|
||||
const ESM::Faction& faction =
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find (factionId);
|
||||
|
||||
return stats.getFactionReputation (factionId)>=faction.mData.mRankData[rank].mFactReaction;
|
||||
}
|
||||
|
||||
MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer)
|
||||
: mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer)
|
||||
{}
|
||||
|
||||
bool MWDialogue::Filter::operator() (const ESM::DialInfo& info) const
|
||||
{
|
||||
return testActor (info) && testPlayer (info) && testSelectStructs (info);
|
||||
}
|
||||
|
||||
const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) const
|
||||
{
|
||||
for (std::vector<ESM::DialInfo>::const_iterator iter = dialogue.mInfo.begin();
|
||||
iter!=dialogue.mInfo.end(); ++iter)
|
||||
if ((*this) (*iter))
|
||||
return &*iter;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
#ifndef GAME_MWDIALOGUE_FILTER_H
|
||||
#define GAME_MWDIALOGUE_FILTER_H
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct DialInfo;
|
||||
struct Dialogue;
|
||||
}
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
class SelectWrapper;
|
||||
|
||||
class Filter
|
||||
{
|
||||
MWWorld::Ptr mActor;
|
||||
int mChoice;
|
||||
bool mTalkedToPlayer;
|
||||
|
||||
bool testActor (const ESM::DialInfo& info) const;
|
||||
///< Is this the right actor for this \a info?
|
||||
|
||||
bool testPlayer (const ESM::DialInfo& info) const;
|
||||
///< Do the player and the cell the player is currently in match \a info?
|
||||
|
||||
bool testSelectStructs (const ESM::DialInfo& info) const;
|
||||
///< Are all select structs matching?
|
||||
|
||||
bool testSelectStruct (const SelectWrapper& select) const;
|
||||
|
||||
bool testSelectStructNumeric (const SelectWrapper& select) const;
|
||||
|
||||
int getSelectStructInteger (const SelectWrapper& select) const;
|
||||
|
||||
bool getSelectStructBoolean (const SelectWrapper& select) const;
|
||||
|
||||
int getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const;
|
||||
|
||||
bool hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
|
||||
int rank) const;
|
||||
|
||||
bool hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, const std::string& factionId,
|
||||
int rank) const;
|
||||
|
||||
public:
|
||||
|
||||
Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer);
|
||||
|
||||
bool operator() (const ESM::DialInfo& info) const;
|
||||
///< \return does the dialogue match?
|
||||
|
||||
const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,311 @@
|
||||
|
||||
#include "selectwrapper.hpp"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string toLower (const std::string& name)
|
||||
{
|
||||
std::string lowerCase;
|
||||
|
||||
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
|
||||
(int(*)(int)) std::tolower);
|
||||
|
||||
return lowerCase;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
bool selectCompareImp (char comp, T1 value1, T2 value2)
|
||||
{
|
||||
switch (comp)
|
||||
{
|
||||
case '0': return value1==value2;
|
||||
case '1': return value1!=value2;
|
||||
case '2': return value1>value2;
|
||||
case '3': return value1>=value2;
|
||||
case '4': return value1<value2;
|
||||
case '5': return value1<=value2;
|
||||
}
|
||||
|
||||
throw std::runtime_error ("unknown compare type in dialogue info select");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1)
|
||||
{
|
||||
if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int ||
|
||||
select.mType==ESM::VT_Long)
|
||||
{
|
||||
return selectCompareImp (select.mSelectRule[4], value1, select.mI);
|
||||
}
|
||||
else if (select.mType==ESM::VT_Float)
|
||||
{
|
||||
return selectCompareImp (select.mSelectRule[4], value1, select.mF);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error (
|
||||
"unsupported variable type in dialogue info select");
|
||||
}
|
||||
}
|
||||
|
||||
MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::decodeFunction() const
|
||||
{
|
||||
int index = 0;
|
||||
|
||||
std::istringstream (mSelect.mSelectRule.substr(2,2)) >> index;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0: return Function_RankLow;
|
||||
case 1: return Function_RankHigh;
|
||||
case 2: return Function_RankRequirement;
|
||||
case 3: return Function_Reputation;
|
||||
case 4: return Function_HealthPercent;
|
||||
case 5: return Function_PCReputation;
|
||||
case 6: return Function_PcLevel;
|
||||
case 7: return Function_PcHealthPercent;
|
||||
case 8: case 9: return Function_PcDynamicStat;
|
||||
case 10: return Function_PcAttribute;
|
||||
case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20:
|
||||
case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30:
|
||||
case 31: case 32: case 33: case 34: case 35: case 36: case 37: return Function_PcSkill;
|
||||
case 38: return Function_PcGender;
|
||||
case 39: return Function_PcExpelled;
|
||||
case 40: return Function_PcCommonDisease;
|
||||
case 41: return Function_PcBlightDisease;
|
||||
case 42: return Function_PcClothingModifier;
|
||||
case 43: return Function_PcCrimeLevel;
|
||||
case 44: return Function_SameGender;
|
||||
case 45: return Function_SameRace;
|
||||
case 46: return Function_SameFaction;
|
||||
case 47: return Function_FactionRankDiff;
|
||||
case 48: return Function_Detected;
|
||||
case 49: return Function_Alarmed;
|
||||
case 50: return Function_Choice;
|
||||
case 51: case 52: case 53: case 54: case 55: case 56: case 57: return Function_PcAttribute;
|
||||
case 58: return Function_PcCorprus;
|
||||
case 59: return Function_Weather;
|
||||
case 60: return Function_PcVampire;
|
||||
case 61: return Function_Level;
|
||||
case 62: return Function_Attacked;
|
||||
case 63: return Function_TalkedToPc;
|
||||
case 64: return Function_PcDynamicStat;
|
||||
case 65: return Function_CreatureTargetted;
|
||||
case 66: return Function_FriendlyHit;
|
||||
case 67: case 68: case 69: case 70: return Function_AiSetting;
|
||||
case 71: return Function_ShouldAttack;
|
||||
case 72: return Function_PCWerewolf;
|
||||
case 73: return Function_WerewolfKills;
|
||||
}
|
||||
|
||||
return Function_False;
|
||||
}
|
||||
|
||||
MWDialogue::SelectWrapper::SelectWrapper (const ESM::DialInfo::SelectStruct& select) : mSelect (select) {}
|
||||
|
||||
MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() const
|
||||
{
|
||||
char type = mSelect.mSelectRule[1];
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case '1': return decodeFunction();
|
||||
case '2': return Function_Global;
|
||||
case '3': return Function_Local;
|
||||
case '4': return Function_Journal;
|
||||
case '5': return Function_Item;
|
||||
case '6': return Function_Dead;
|
||||
case '7': return Function_Id;
|
||||
case '8': return Function_Faction;
|
||||
case '9': return Function_Class;
|
||||
case 'A': return Function_Race;
|
||||
case 'B': return Function_Cell;
|
||||
case 'C': return Function_Local;
|
||||
}
|
||||
|
||||
return Function_None;
|
||||
}
|
||||
|
||||
int MWDialogue::SelectWrapper::getArgument() const
|
||||
{
|
||||
if (mSelect.mSelectRule[1]!='1')
|
||||
return 0;
|
||||
|
||||
int index = 0;
|
||||
|
||||
std::istringstream (mSelect.mSelectRule.substr(2,2)) >> index;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
// AI settings
|
||||
case 67: return 1;
|
||||
case 68: return 0;
|
||||
case 69: return 3;
|
||||
case 70: return 2;
|
||||
|
||||
// attributes
|
||||
case 10: return 0;
|
||||
case 51: return 1;
|
||||
case 52: return 2;
|
||||
case 53: return 3;
|
||||
case 54: return 4;
|
||||
case 55: return 5;
|
||||
case 56: return 6;
|
||||
case 57: return 7;
|
||||
|
||||
// skills
|
||||
case 11: return 0;
|
||||
case 12: return 1;
|
||||
case 13: return 2;
|
||||
case 14: return 3;
|
||||
case 15: return 4;
|
||||
case 16: return 5;
|
||||
case 17: return 6;
|
||||
case 18: return 7;
|
||||
case 19: return 8;
|
||||
case 20: return 9;
|
||||
case 21: return 10;
|
||||
case 22: return 11;
|
||||
case 23: return 12;
|
||||
case 24: return 13;
|
||||
case 25: return 14;
|
||||
case 26: return 15;
|
||||
case 27: return 16;
|
||||
case 28: return 17;
|
||||
case 29: return 18;
|
||||
case 30: return 19;
|
||||
case 31: return 20;
|
||||
case 32: return 21;
|
||||
case 33: return 22;
|
||||
case 34: return 23;
|
||||
case 35: return 24;
|
||||
case 36: return 25;
|
||||
case 37: return 26;
|
||||
|
||||
// dynamic stats
|
||||
case 8: return 1;
|
||||
case 9: return 2;
|
||||
case 64: return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const
|
||||
{
|
||||
static const Function integerFunctions[] =
|
||||
{
|
||||
Function_Journal, Function_Item, Function_Dead,
|
||||
Function_Choice,
|
||||
Function_AiSetting,
|
||||
Function_PcAttribute, Function_PcSkill,
|
||||
Function_FriendlyHit,
|
||||
Function_PcLevel, Function_PcGender, Function_PcClothingModifier,
|
||||
Function_PcCrimeLevel,
|
||||
Function_RankRequirement,
|
||||
Function_Level, Function_PCReputation,
|
||||
Function_Weather,
|
||||
Function_Reputation, Function_FactionRankDiff,
|
||||
Function_WerewolfKills,
|
||||
Function_RankLow, Function_RankHigh,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
||||
static const Function numericFunctions[] =
|
||||
{
|
||||
Function_Global, Function_Local,
|
||||
Function_PcDynamicStat, Function_PcHealthPercent,
|
||||
Function_HealthPercent,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
||||
static const Function booleanFunctions[] =
|
||||
{
|
||||
Function_False,
|
||||
Function_Id, Function_Faction, Function_Class, Function_Race, Function_Cell,
|
||||
Function_SameGender, Function_SameRace, Function_SameFaction,
|
||||
Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus,
|
||||
Function_PcExpelled,
|
||||
Function_PcVampire, Function_TalkedToPc,
|
||||
Function_Alarmed, Function_Detected,
|
||||
Function_Attacked, Function_ShouldAttack,
|
||||
Function_CreatureTargetted,
|
||||
Function_PCWerewolf,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
||||
Function function = getFunction();
|
||||
|
||||
for (int i=0; integerFunctions[i]!=Function_None; ++i)
|
||||
if (integerFunctions[i]==function)
|
||||
return Type_Integer;
|
||||
|
||||
for (int i=0; numericFunctions[i]!=Function_None; ++i)
|
||||
if (numericFunctions[i]==function)
|
||||
return Type_Numeric;
|
||||
|
||||
for (int i=0; booleanFunctions[i]!=Function_None; ++i)
|
||||
if (booleanFunctions[i]==function)
|
||||
return Type_Boolean;
|
||||
|
||||
return Type_None;
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::isInverted() const
|
||||
{
|
||||
char type = mSelect.mSelectRule[1];
|
||||
|
||||
return type=='7' || type=='8' || type=='9' || type=='A' || type=='B' || type=='C';
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::isNpcOnly() const
|
||||
{
|
||||
static const Function functions[] =
|
||||
{
|
||||
Function_Faction, SelectWrapper::Function_Class, SelectWrapper::Function_Race,
|
||||
Function_SameGender, Function_SameRace, Function_SameFaction,
|
||||
Function_PcSkill,
|
||||
Function_PcExpelled,
|
||||
Function_PcVampire,
|
||||
Function_PcCrimeLevel,
|
||||
Function_RankRequirement,
|
||||
Function_Reputation, Function_FactionRankDiff,
|
||||
Function_PCWerewolf, Function_WerewolfKills,
|
||||
Function_RankLow, Function_RankHigh,
|
||||
Function_None // end marker
|
||||
};
|
||||
|
||||
Function function = getFunction();
|
||||
|
||||
for (int i=0; functions[i]!=Function_None; ++i)
|
||||
if (functions[i]==function)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::selectCompare (int value) const
|
||||
{
|
||||
return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::selectCompare (float value) const
|
||||
{
|
||||
return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR
|
||||
}
|
||||
|
||||
bool MWDialogue::SelectWrapper::selectCompare (bool value) const
|
||||
{
|
||||
return selectCompareImp (mSelect, static_cast<int> (value))!=isInverted(); // logic XOR
|
||||
}
|
||||
|
||||
std::string MWDialogue::SelectWrapper::getName() const
|
||||
{
|
||||
return toLower (mSelect.mSelectRule.substr (5));
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
#ifndef GAME_MWDIALOGUE_SELECTWRAPPER_H
|
||||
#define GAME_MWDIALOGUE_SELECTWRAPPER_H
|
||||
|
||||
#include <components/esm/loadinfo.hpp>
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
class SelectWrapper
|
||||
{
|
||||
const ESM::DialInfo::SelectStruct& mSelect;
|
||||
|
||||
public:
|
||||
|
||||
enum Function
|
||||
{
|
||||
Function_None, Function_False,
|
||||
Function_Journal,
|
||||
Function_Item,
|
||||
Function_Dead,
|
||||
Function_Id,
|
||||
Function_Faction,
|
||||
Function_Class,
|
||||
Function_Race,
|
||||
Function_Cell,
|
||||
Function_Local,
|
||||
Function_Global,
|
||||
Function_SameGender, Function_SameRace, Function_SameFaction,
|
||||
Function_Choice,
|
||||
Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus,
|
||||
Function_AiSetting,
|
||||
Function_PcAttribute, Function_PcSkill,
|
||||
Function_PcExpelled,
|
||||
Function_PcVampire,
|
||||
Function_FriendlyHit,
|
||||
Function_TalkedToPc,
|
||||
Function_PcLevel, Function_PcHealthPercent, Function_PcDynamicStat,
|
||||
Function_PcGender, Function_PcClothingModifier, Function_PcCrimeLevel,
|
||||
Function_RankRequirement,
|
||||
Function_HealthPercent, Function_Level, Function_PCReputation,
|
||||
Function_Weather,
|
||||
Function_Reputation, Function_Alarmed, Function_FactionRankDiff, Function_Detected,
|
||||
Function_Attacked, Function_ShouldAttack,
|
||||
Function_CreatureTargetted,
|
||||
Function_PCWerewolf, Function_WerewolfKills,
|
||||
Function_RankLow, Function_RankHigh
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
Type_None,
|
||||
Type_Integer,
|
||||
Type_Numeric,
|
||||
Type_Boolean
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Function decodeFunction() const;
|
||||
|
||||
public:
|
||||
|
||||
SelectWrapper (const ESM::DialInfo::SelectStruct& select);
|
||||
|
||||
Function getFunction() const;
|
||||
|
||||
int getArgument() const;
|
||||
|
||||
Type getType() const;
|
||||
|
||||
bool isInverted() const;
|
||||
|
||||
bool isNpcOnly() const;
|
||||
///< \attention Do not call any of the select functions for this select struct!
|
||||
|
||||
bool selectCompare (int value) const;
|
||||
|
||||
bool selectCompare (float value) const;
|
||||
|
||||
bool selectCompare (bool value) const;
|
||||
|
||||
std::string getName() const;
|
||||
///< Return case-smashed name.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue