903 lines
27 KiB
C++
903 lines
27 KiB
C++
#include "ScaleformCallbacks.h"
|
|
#include "ScaleformMovie.h"
|
|
#include "ScaleformExtendedData.h"
|
|
#include "GameData.h"
|
|
#include "GameForms.h"
|
|
#include "GameObjects.h"
|
|
#include "GameReferences.h"
|
|
#include "GameExtraData.h"
|
|
#include "GameRTTI.h"
|
|
#include "GameMenus.h"
|
|
|
|
// Helpers
|
|
double round(double r)
|
|
{
|
|
return (r >= 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
|
|
}
|
|
|
|
void RegisterUnmanagedString(GFxValue * dst, const char * name, const char * str)
|
|
{
|
|
GFxValue fxValue;
|
|
|
|
fxValue.SetString(str);
|
|
|
|
dst->SetMember(name, &fxValue);
|
|
}
|
|
|
|
void RegisterString(GFxValue * dst, GFxMovieView * view, const char * name, const char * str)
|
|
{
|
|
GFxValue fxValue;
|
|
|
|
view->CreateString(&fxValue, str);
|
|
|
|
dst->SetMember(name, &fxValue);
|
|
}
|
|
|
|
void RegisterWideString(GFxValue * dst, GFxMovieView * view, const char * name, const wchar_t * str)
|
|
{
|
|
GFxValue fxValue;
|
|
|
|
view->CreateWideString(&fxValue, str);
|
|
|
|
dst->SetMember(name, &fxValue);
|
|
}
|
|
|
|
void RegisterNumber(GFxValue * dst, const char * name, double value)
|
|
{
|
|
GFxValue fxValue;
|
|
|
|
fxValue.SetNumber(value);
|
|
|
|
dst->SetMember(name, &fxValue);
|
|
}
|
|
|
|
void RegisterBool(GFxValue * dst, const char * name, bool value)
|
|
{
|
|
GFxValue fxValue;
|
|
fxValue.SetBool(value);
|
|
dst->SetMember(name, &fxValue);
|
|
}
|
|
|
|
void RegisterKeywords(GFxValue * pFxVal, GFxMovieView * view, BGSKeywordForm * keywordForm)
|
|
{
|
|
GFxValue keywordRoot;
|
|
view->CreateObject(&keywordRoot);
|
|
|
|
// Add all keywords as boolean properties with value true
|
|
|
|
UInt32 count = keywordForm->numKeywords;
|
|
BGSKeyword ** keywords = keywordForm->keywords;
|
|
if(keywords)
|
|
{
|
|
for(int i = 0; i < count; i++)
|
|
{
|
|
BGSKeyword * pKey = keywords[i];
|
|
if(pKey)
|
|
{
|
|
const char * keyString = pKey->keyword.Get();
|
|
if(keyString)
|
|
{
|
|
RegisterBool(&keywordRoot, keyString, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pFxVal->SetMember("keywords", &keywordRoot);
|
|
}
|
|
|
|
class FormListExtender : public BGSListForm::Visitor
|
|
{
|
|
GFxValue * m_array;
|
|
GFxMovieView * m_movie;
|
|
bool m_bExtra;
|
|
bool m_bRecursive;
|
|
|
|
public:
|
|
FormListExtender::FormListExtender(GFxValue * formArray, GFxMovieView * movie, bool bExtra, bool bRecursive) : m_array(formArray), m_movie(movie), m_bExtra(bExtra), m_bRecursive(bRecursive) { }
|
|
virtual bool Accept(TESForm * form)
|
|
{
|
|
if(form) {
|
|
GFxValue arrArg;
|
|
m_movie->CreateObject(&arrArg);
|
|
scaleformExtend::FormData(&arrArg, m_movie, form, m_bRecursive ? m_bExtra : false, m_bRecursive);
|
|
m_array->PushBack(&arrArg);
|
|
}
|
|
return false;
|
|
};
|
|
};
|
|
|
|
// Data extensions
|
|
namespace scaleformExtend
|
|
{
|
|
void CommonItemData(GFxValue* pFxVal, TESForm * pForm)
|
|
{
|
|
if(!pFxVal || !pForm || !pFxVal->IsObject())
|
|
return;
|
|
|
|
RegisterNumber(pFxVal, "formType", (double)pForm->GetFormType());
|
|
RegisterNumber(pFxVal, "formId", (double)pForm->formID);
|
|
}
|
|
|
|
void StandardItemData(GFxValue * pFxVal, TESForm * pForm, InventoryEntryData * pEntry)
|
|
{
|
|
if(!pForm || !pFxVal || !pFxVal->IsObject())
|
|
return;
|
|
|
|
switch(pForm->GetFormType())
|
|
{
|
|
case kFormType_Armor:
|
|
{
|
|
TESObjectARMO * pArmor = DYNAMIC_CAST(pForm, TESForm, TESObjectARMO);
|
|
if(pArmor)
|
|
{
|
|
RegisterNumber(pFxVal, "partMask", pArmor->bipedObject.data.parts);
|
|
RegisterNumber(pFxVal, "weightClass", pArmor->bipedObject.data.weightClass);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kFormType_Ammo:
|
|
{
|
|
TESAmmo * pAmmo = DYNAMIC_CAST(pForm, TESForm, TESAmmo);
|
|
if(pAmmo)
|
|
{
|
|
RegisterNumber(pFxVal, "flags", pAmmo->settings.flags);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kFormType_Weapon:
|
|
{
|
|
TESObjectWEAP * pWeapon = DYNAMIC_CAST(pForm, TESForm, TESObjectWEAP);
|
|
if(pWeapon)
|
|
{
|
|
RegisterNumber(pFxVal, "subType", pWeapon->type()); // DEPRECATED
|
|
RegisterNumber(pFxVal, "weaponType", pWeapon->type());
|
|
RegisterNumber(pFxVal, "speed", pWeapon->speed());
|
|
RegisterNumber(pFxVal, "reach", pWeapon->reach());
|
|
RegisterNumber(pFxVal, "stagger", pWeapon->stagger());
|
|
RegisterNumber(pFxVal, "critDamage", pWeapon->critDamage());
|
|
RegisterNumber(pFxVal, "minRange", pWeapon->minRange());
|
|
RegisterNumber(pFxVal, "maxRange", pWeapon->maxRange());
|
|
RegisterNumber(pFxVal, "baseDamage", pWeapon->damage.GetAttackDamage());
|
|
|
|
BGSEquipSlot * equipSlot = pWeapon->equipType.GetEquipSlot();
|
|
if (equipSlot)
|
|
RegisterNumber(pFxVal, "equipSlot", equipSlot->formID);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kFormType_SoulGem:
|
|
{
|
|
TESSoulGem * soulGem = DYNAMIC_CAST(pForm, TESForm, TESSoulGem);
|
|
if(soulGem)
|
|
{
|
|
RegisterNumber(pFxVal, "gemSize", soulGem->gemSize);
|
|
RegisterNumber(pFxVal, "soulSize", pEntry ? CALL_MEMBER_FN(pEntry,GetSoulLevel)() : soulGem->soulSize);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kFormType_Potion:
|
|
{
|
|
AlchemyItem * pAlchemy = DYNAMIC_CAST(pForm, TESForm, AlchemyItem);
|
|
if(pAlchemy)
|
|
{
|
|
RegisterNumber(pFxVal, "flags", pAlchemy->itemData.flags);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kFormType_Book:
|
|
{
|
|
TESObjectBOOK * pBook = DYNAMIC_CAST(pForm, TESForm, TESObjectBOOK);
|
|
if(pBook)
|
|
{
|
|
RegisterNumber(pFxVal, "flags", pBook->data.flags);
|
|
RegisterNumber(pFxVal, "bookType", pBook->data.type);
|
|
switch(pBook->data.GetSanitizedType())
|
|
{
|
|
case TESObjectBOOK::Data::kType_Skill:
|
|
RegisterNumber(pFxVal, "teachesSkill", pBook->data.teaches.skill);
|
|
break;
|
|
|
|
case TESObjectBOOK::Data::kType_Spell:
|
|
{
|
|
double formID = -1;
|
|
|
|
if(pBook->data.teaches.spell)
|
|
formID = pBook->data.teaches.spell->formID;
|
|
|
|
RegisterNumber(pFxVal, "teachesSpell", formID);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void MagicItemData(GFxValue * pFxVal, GFxMovieView * movieView, TESForm * pForm, bool bExtra, bool bRecursive)
|
|
{
|
|
if(!pFxVal || !pForm || !pFxVal->IsObject())
|
|
return;
|
|
|
|
switch(pForm->GetFormType())
|
|
{
|
|
case kFormType_Spell:
|
|
case kFormType_ScrollItem:
|
|
case kFormType_Ingredient:
|
|
case kFormType_Potion:
|
|
case kFormType_Enchantment:
|
|
{
|
|
MagicItem * pMagicItem = DYNAMIC_CAST(pForm, TESForm, MagicItem);
|
|
if(pMagicItem)
|
|
{
|
|
if(pMagicItem->fullName.name.data)
|
|
RegisterUnmanagedString(pFxVal, "spellName", pMagicItem->fullName.name.data);
|
|
|
|
MagicItem::EffectItem * pEffect = CALL_MEMBER_FN(pMagicItem, GetCostliestEffectItem)(5, false);
|
|
if(pEffect && pEffect->mgef)
|
|
{
|
|
RegisterNumber(pFxVal, "magnitude", pEffect->magnitude);
|
|
RegisterNumber(pFxVal, "duration", pEffect->duration);
|
|
RegisterNumber(pFxVal, "area", pEffect->area);
|
|
|
|
// PLB: Normally I'd have this as a separate object but SkyUI is already using this
|
|
scaleformExtend::MagicItemData(pFxVal, movieView, pEffect->mgef, bRecursive ? bExtra : false, bRecursive);
|
|
}
|
|
}
|
|
|
|
SpellItem * pSpellItem = DYNAMIC_CAST(pMagicItem, MagicItem, SpellItem);
|
|
if(pSpellItem)
|
|
{
|
|
RegisterNumber(pFxVal, "spellType", pSpellItem->data.type);
|
|
RegisterNumber(pFxVal, "trueCost", pSpellItem->GetMagickaCost());
|
|
|
|
BGSEquipSlot * equipSlot = pSpellItem->equipType.GetEquipSlot();
|
|
if (equipSlot)
|
|
RegisterNumber(pFxVal, "equipSlot", equipSlot->formID);
|
|
}
|
|
|
|
AlchemyItem * pAlchemyItem = DYNAMIC_CAST(pMagicItem, MagicItem, AlchemyItem);
|
|
if(pAlchemyItem)
|
|
{
|
|
if(pAlchemyItem->itemData.useSound) {
|
|
GFxValue useSound;
|
|
movieView->CreateObject(&useSound);
|
|
scaleformExtend::FormData(&useSound, movieView, pAlchemyItem->itemData.useSound, bRecursive ? bExtra : false, bRecursive);
|
|
pFxVal->SetMember("useSound", &useSound);
|
|
}
|
|
}
|
|
|
|
EnchantmentItem * pEnchantItem = DYNAMIC_CAST(pMagicItem, MagicItem, EnchantmentItem);
|
|
if(pEnchantItem)
|
|
{
|
|
RegisterNumber(pFxVal, "flags", (double)pMagicItem->flags);
|
|
|
|
GFxValue baseEnchant;
|
|
movieView->CreateObject(&baseEnchant);
|
|
scaleformExtend::FormData(&baseEnchant, movieView, pEnchantItem->data.baseEnchantment, bRecursive ? bExtra : false, bRecursive);
|
|
pFxVal->SetMember("baseEnchant", &baseEnchant);
|
|
|
|
GFxValue restrictions;
|
|
movieView->CreateObject(&restrictions);
|
|
scaleformExtend::FormData(&restrictions, movieView, pEnchantItem->data.restrictions, bRecursive ? bExtra : false, bRecursive);
|
|
pFxVal->SetMember("restrictions", &restrictions);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kFormType_EffectSetting:
|
|
{
|
|
EffectSetting * pEffectSetting = DYNAMIC_CAST(pForm, TESForm, EffectSetting);
|
|
if(pEffectSetting)
|
|
{
|
|
if(pEffectSetting->fullName.name.data)
|
|
RegisterUnmanagedString(pFxVal, "effectName", pEffectSetting->fullName.name.data);
|
|
|
|
RegisterNumber(pFxVal, "subType", pEffectSetting->school()); // DEPRECATED
|
|
RegisterNumber(pFxVal, "effectFlags", pEffectSetting->properties.flags);
|
|
RegisterNumber(pFxVal, "school", pEffectSetting->school());
|
|
RegisterNumber(pFxVal, "skillLevel", pEffectSetting->level());
|
|
RegisterNumber(pFxVal, "archetype", pEffectSetting->properties.archetype);
|
|
RegisterNumber(pFxVal, "deliveryType", pEffectSetting->properties.deliveryType);
|
|
RegisterNumber(pFxVal, "castTime", pEffectSetting->properties.castingTime);
|
|
RegisterNumber(pFxVal, "delayTime", pEffectSetting->properties.delayTime);
|
|
RegisterNumber(pFxVal, "actorValue", pEffectSetting->properties.primaryValue);
|
|
RegisterNumber(pFxVal, "castType", pEffectSetting->properties.castType);
|
|
RegisterNumber(pFxVal, "magicType", pEffectSetting->properties.resistance);
|
|
}
|
|
}
|
|
break;
|
|
case kFormType_Shout:
|
|
{
|
|
TESShout * pShout = DYNAMIC_CAST(pForm, TESForm, TESShout);
|
|
if(pShout)
|
|
{
|
|
if(pShout->fullName.name.data)
|
|
RegisterUnmanagedString(pFxVal, "fullName", pShout->fullName.name.data);
|
|
|
|
// Words
|
|
GFxValue words;
|
|
movieView->CreateArray(&words);
|
|
for(int i = 0; i < pShout->Words::kNumWords; i++)
|
|
{
|
|
GFxValue word;
|
|
movieView->CreateObject(&word);
|
|
|
|
if(pShout->words[i].word && pShout->words[i].word->fullName.name.data)
|
|
RegisterUnmanagedString(&word, "word", pShout->words[i].word->fullName.name.data);
|
|
|
|
if(pShout->words[i].word && pShout->words[i].word->word.data)
|
|
RegisterUnmanagedString(&word, "fullName", pShout->words[i].word->word.data);
|
|
|
|
RegisterNumber(&word, "recoveryTime", pShout->words[i].recoverytime);
|
|
|
|
// Spell Object
|
|
scaleformExtend::FormData(&word, movieView, pShout->words[i].spell, bRecursive ? bExtra : false, bRecursive);
|
|
words.PushBack(&word);
|
|
}
|
|
pFxVal->SetMember("words", &words);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ActorData(GFxValue * pFxVal, GFxMovieView * movieView, TESForm * pForm, bool bExtra, bool bRecursive)
|
|
{
|
|
if(!pForm || !pFxVal || !pFxVal->IsObject())
|
|
return;
|
|
|
|
switch(pForm->GetFormType())
|
|
{
|
|
case kFormType_Race:
|
|
{
|
|
TESRace * pRace = DYNAMIC_CAST(pForm, TESForm, TESRace);
|
|
if(pRace)
|
|
{
|
|
if(pRace->fullName.name.data)
|
|
RegisterUnmanagedString(pFxVal, "fullName", pRace->fullName.name.data);
|
|
|
|
if(pRace->editorId.data)
|
|
RegisterUnmanagedString(pFxVal, "editorId", pRace->editorId.data);
|
|
|
|
// Spells
|
|
GFxValue spells;
|
|
movieView->CreateArray(&spells);
|
|
for(int i = 0; i < pRace->spellList.GetSpellCount(); i++)
|
|
{
|
|
GFxValue spell;
|
|
movieView->CreateObject(&spell);
|
|
scaleformExtend::FormData(&spell, movieView, pRace->spellList.GetNthSpell(i), bRecursive ? bExtra : false, bRecursive);
|
|
spells.PushBack(&spell);
|
|
}
|
|
pFxVal->SetMember("spells", &spells);
|
|
|
|
// Shouts
|
|
GFxValue shouts;
|
|
movieView->CreateArray(&shouts);
|
|
for(int i = 0; i < pRace->spellList.GetShoutCount(); i++)
|
|
{
|
|
GFxValue shout;
|
|
movieView->CreateObject(&shout);
|
|
scaleformExtend::FormData(&shout, movieView, pRace->spellList.GetNthShout(i), bRecursive ? bExtra : false, bRecursive);
|
|
shouts.PushBack(&shout);
|
|
}
|
|
pFxVal->SetMember("shouts", &shouts);
|
|
|
|
GFxValue bonuses;
|
|
movieView->CreateArray(&bonuses);
|
|
for(int i = 0; i < TESRace::kRace_NumSkillBonuses; i++)
|
|
{
|
|
GFxValue skillBonus;
|
|
movieView->CreateObject(&skillBonus);
|
|
RegisterNumber(&skillBonus, "skill", pRace->data.skillBonus[i].skill);
|
|
RegisterNumber(&skillBonus, "bonus", pRace->data.skillBonus[i].bonus);
|
|
bonuses.PushBack(&skillBonus);
|
|
}
|
|
pFxVal->SetMember("skillBonuses", &bonuses);
|
|
}
|
|
}
|
|
break;
|
|
case kFormType_NPC:
|
|
{
|
|
TESNPC * pNPC = DYNAMIC_CAST(pForm, TESForm, TESNPC);
|
|
if(pNPC)
|
|
{
|
|
if(pNPC->fullName.name.data)
|
|
RegisterUnmanagedString(pFxVal, "fullName", pNPC->fullName.name.data);
|
|
if(pNPC->shortName.data)
|
|
RegisterUnmanagedString(pFxVal, "shortName", pNPC->shortName.data);
|
|
|
|
RegisterNumber(pFxVal, "weight", pNPC->weight);
|
|
|
|
bool isLevelMult = (pNPC->actorData.flags & TESActorBaseData::kFlag_PCLevelMult) == TESActorBaseData::kFlag_PCLevelMult;
|
|
if(isLevelMult)
|
|
RegisterNumber(pFxVal, "levelMult", (double)pNPC->actorData.level / 1000.0);
|
|
else
|
|
RegisterNumber(pFxVal, "level", (double)pNPC->actorData.level);
|
|
|
|
RegisterNumber(pFxVal, "minLevel", (double)pNPC->actorData.minLevel);
|
|
RegisterNumber(pFxVal, "maxLevel", (double)pNPC->actorData.maxLevel);
|
|
|
|
GFxValue race;
|
|
movieView->CreateObject(&race);
|
|
scaleformExtend::FormData(&race, movieView, pNPC->race.race, bRecursive ? bExtra : false, bRecursive);
|
|
pFxVal->SetMember("race", &race);
|
|
|
|
// Spells
|
|
GFxValue spells;
|
|
movieView->CreateArray(&spells);
|
|
for(int i = 0; i < pNPC->spellList.GetSpellCount(); i++)
|
|
{
|
|
GFxValue spell;
|
|
movieView->CreateObject(&spell);
|
|
scaleformExtend::FormData(&spell, movieView, pNPC->spellList.GetNthSpell(i), bRecursive ? bExtra : false, bRecursive);
|
|
spells.PushBack(&spell);
|
|
}
|
|
pFxVal->SetMember("spells", &spells);
|
|
|
|
// Shouts
|
|
GFxValue shouts;
|
|
movieView->CreateArray(&shouts);
|
|
for(int i = 0; i < pNPC->spellList.GetShoutCount(); i++)
|
|
{
|
|
GFxValue shout;
|
|
movieView->CreateObject(&shout);
|
|
scaleformExtend::FormData(&shout, movieView, pNPC->spellList.GetNthShout(i), bRecursive ? bExtra : false, bRecursive);
|
|
shouts.PushBack(&shout);
|
|
}
|
|
pFxVal->SetMember("shouts", &shouts);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kFormType_Character:
|
|
{
|
|
Actor * pActor = DYNAMIC_CAST(pForm, TESForm, Actor);
|
|
if(pActor)
|
|
{
|
|
// ActorBase as Object
|
|
GFxValue actorBase;
|
|
movieView->CreateObject(&actorBase);
|
|
|
|
scaleformExtend::FormData(&actorBase, movieView, pActor->baseForm, bRecursive ? bExtra : false, bRecursive);
|
|
pFxVal->SetMember("actorBase", &actorBase);
|
|
|
|
RegisterUnmanagedString(pFxVal, "fullName", CALL_MEMBER_FN(pActor, GetReferenceName)());
|
|
|
|
// Spells as Array
|
|
GFxValue addedSpells;
|
|
movieView->CreateArray(&addedSpells);
|
|
|
|
for(int i = 0; i < pActor->addedSpells.Length(); i++)
|
|
{
|
|
GFxValue spell;
|
|
movieView->CreateObject(&spell);
|
|
scaleformExtend::FormData(&spell, movieView, pActor->addedSpells.Get(i), bRecursive ? bExtra : false, bRecursive);
|
|
addedSpells.PushBack(&spell);
|
|
}
|
|
|
|
pFxVal->SetMember("spells", &addedSpells);
|
|
|
|
// ActiveEffects as Array
|
|
GFxValue activeEffects;
|
|
movieView->CreateArray(&activeEffects);
|
|
|
|
tList<ActiveEffect> * effects = pActor->magicTarget.GetActiveEffects();
|
|
if(effects)
|
|
{
|
|
for(int i = 0; i < effects->Count(); i++)
|
|
{
|
|
GFxValue effect;
|
|
movieView->CreateObject(&effect);
|
|
|
|
ActiveEffect * pEffect = effects->GetNthItem(i);
|
|
|
|
if(pEffect->item)
|
|
scaleformExtend::MagicItemData(&effect, movieView, pEffect->item, bRecursive ? bExtra : false, bRecursive);
|
|
|
|
RegisterNumber(&effect, "elapsed", pEffect->elapsed);
|
|
RegisterNumber(&effect, "duration", pEffect->duration);
|
|
RegisterNumber(&effect, "magnitude", pEffect->magnitude);
|
|
RegisterBool(&effect, "inactive", (pEffect->flags & ActiveEffect::kFlag_Inactive) == ActiveEffect::kFlag_Inactive);
|
|
|
|
// ActiveEffect
|
|
if(pEffect->effect && pEffect->effect->mgef)
|
|
scaleformExtend::MagicItemData(&effect, movieView, pEffect->effect->mgef, bRecursive ? bExtra : false, bRecursive);
|
|
|
|
activeEffects.PushBack(&effect);
|
|
}
|
|
}
|
|
pFxVal->SetMember("activeEffects", &activeEffects);
|
|
|
|
GFxValue actorValues;
|
|
movieView->CreateArray(&actorValues);
|
|
|
|
for(int i = 0; i < ActorValueList::kNumActorValues; i++)
|
|
{
|
|
GFxValue actorValue;
|
|
movieView->CreateObject(&actorValue);
|
|
RegisterNumber(&actorValue, "current", pActor->actorValueOwner.GetCurrent(i));
|
|
RegisterNumber(&actorValue, "maximum", pActor->actorValueOwner.GetMaximum(i));
|
|
RegisterNumber(&actorValue, "base", pActor->actorValueOwner.GetBase(i));
|
|
actorValues.PushBack(&actorValue);
|
|
}
|
|
|
|
pFxVal->SetMember("actorValues", &actorValues);
|
|
}
|
|
PlayerCharacter* pPC = DYNAMIC_CAST(pForm, TESForm, PlayerCharacter);
|
|
if(pPC)
|
|
{
|
|
RegisterNumber(pFxVal, "perkPoints", (double)pPC->numPerkPoints);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void FormListData(GFxValue * pFxVal, GFxMovieView * movieView, TESForm * pForm, bool bExtra, bool bRecursive)
|
|
{
|
|
if(!pForm || !pFxVal || !pFxVal->IsObject())
|
|
return;
|
|
|
|
switch(pForm->GetFormType())
|
|
{
|
|
case kFormType_List:
|
|
{
|
|
BGSListForm * formList = DYNAMIC_CAST(pForm, TESForm, BGSListForm);
|
|
if(formList)
|
|
{
|
|
GFxValue formArray;
|
|
movieView->CreateArray(&formArray);
|
|
|
|
FormListExtender extender(&formArray, movieView, bExtra, bRecursive);
|
|
formList->Visit(extender);
|
|
|
|
pFxVal->SetMember("forms", &formArray);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MiscData(GFxValue * pFxVal, GFxMovieView * movieView, TESForm * pForm, bool bExtra, bool bRecursive)
|
|
{
|
|
if(!pForm || !pFxVal || !pFxVal->IsObject())
|
|
return;
|
|
|
|
switch(pForm->GetFormType())
|
|
{
|
|
case kFormType_Message:
|
|
{
|
|
BGSMessage * message = DYNAMIC_CAST(pForm, TESForm, BGSMessage);
|
|
if(message)
|
|
{
|
|
GFxValue btnArray;
|
|
movieView->CreateArray(&btnArray);
|
|
BSFixedString * btnText;
|
|
for(int i = 0; i < message->buttons.Count(); i++)
|
|
{
|
|
GFxValue fxValue;
|
|
btnText = message->buttons.GetNthItem(i);
|
|
if(btnText) {
|
|
fxValue.SetString(btnText->data);
|
|
btnArray.PushBack(&fxValue);
|
|
}
|
|
}
|
|
|
|
pFxVal->SetMember("buttons", &btnArray);
|
|
RegisterUnmanagedString(pFxVal, "message", message->GetDescription().c_str());
|
|
}
|
|
}
|
|
break;
|
|
case kFormType_Quest:
|
|
{
|
|
TESQuest * quest = DYNAMIC_CAST(pForm, TESForm, TESQuest);
|
|
if(quest)
|
|
{
|
|
RegisterUnmanagedString(pFxVal, "fullName", quest->fullName.name.data);
|
|
RegisterNumber(pFxVal, "flags", quest->unk0D8.flags);
|
|
RegisterNumber(pFxVal, "priority", quest->unk0D8.priority);
|
|
RegisterUnmanagedString(pFxVal, "editorId", quest->questID.Get());
|
|
|
|
GFxValue aliasArray;
|
|
|
|
movieView->CreateArray(&aliasArray);
|
|
|
|
for(int i = 0; i < quest->aliases.count; i++)
|
|
{
|
|
BGSBaseAlias* alias;
|
|
if(quest->aliases.GetNthItem(i, alias)) {
|
|
GFxValue arrArg;
|
|
movieView->CreateObject(&arrArg);
|
|
RegisterUnmanagedString(&arrArg, "name", alias->name.data);
|
|
RegisterNumber(&arrArg, "id", alias->aliasId);
|
|
RegisterNumber(&arrArg, "flags", alias->flags);
|
|
aliasArray.PushBack(&arrArg);
|
|
}
|
|
}
|
|
|
|
pFxVal->SetMember("aliases", &aliasArray);
|
|
}
|
|
}
|
|
break;
|
|
case kFormType_HeadPart:
|
|
{
|
|
BGSHeadPart * headPart = DYNAMIC_CAST(pForm, TESForm, BGSHeadPart);
|
|
if(headPart)
|
|
{
|
|
RegisterUnmanagedString(pFxVal, "fullName", headPart->fullName.name.data);
|
|
RegisterUnmanagedString(pFxVal, "partName", headPart->partName.data);
|
|
RegisterNumber(pFxVal, "partFlags", headPart->partFlags);
|
|
RegisterNumber(pFxVal, "partType", headPart->type);
|
|
|
|
RegisterUnmanagedString(pFxVal, "modelPath", headPart->model.GetModelName());
|
|
RegisterUnmanagedString(pFxVal, "chargenMorphPath", headPart->chargenMorph.GetModelName());
|
|
RegisterUnmanagedString(pFxVal, "raceMorphPath", headPart->raceMorph.GetModelName());
|
|
|
|
GFxValue extraParts;
|
|
movieView->CreateArray(&extraParts);
|
|
for(int i = 0; i < headPart->extraParts.count; i++)
|
|
{
|
|
BGSHeadPart* extraPart;
|
|
if(headPart->extraParts.GetNthItem(i, extraPart)) {
|
|
GFxValue arrArg;
|
|
movieView->CreateObject(&arrArg);
|
|
scaleformExtend::FormData(&arrArg, movieView, extraPart, bRecursive ? bExtra : false, bRecursive);
|
|
extraParts.PushBack(&arrArg);
|
|
}
|
|
}
|
|
|
|
pFxVal->SetMember("extraParts", &extraParts);
|
|
|
|
GFxValue validRaces;
|
|
movieView->CreateObject(&validRaces);
|
|
scaleformExtend::FormData(&validRaces, movieView, headPart->validRaces, bRecursive ? bExtra : false, bRecursive);
|
|
pFxVal->SetMember("validRaces", &validRaces);
|
|
|
|
GFxValue textureSet;
|
|
movieView->CreateObject(&textureSet);
|
|
scaleformExtend::FormData(&textureSet, movieView, headPart->textureSet, bRecursive ? bExtra : false, bRecursive);
|
|
pFxVal->SetMember("textureSet", &textureSet);
|
|
}
|
|
}
|
|
break;
|
|
case kFormType_TextureSet:
|
|
{
|
|
BGSTextureSet * textureSet = DYNAMIC_CAST(pForm, TESForm, BGSTextureSet);
|
|
if(textureSet)
|
|
{
|
|
GFxValue textureArray;
|
|
movieView->CreateArray(&textureArray);
|
|
for(int i = 0; i < BGSTextureSet::kNumTextures; i++)
|
|
{
|
|
GFxValue strArg;
|
|
strArg.SetString(textureSet->texturePaths[i].str.data);
|
|
textureArray.PushBack(&strArg);
|
|
}
|
|
|
|
pFxVal->SetMember("textures", &textureArray);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Convenience function, maybe combine all other functions into this one anyway?
|
|
// bExtra - Adds all extra data other than FormId and FormType
|
|
// bRecursive - Processes child forms
|
|
void FormData(GFxValue * pFxVal, GFxMovieView * movieView, TESForm * pForm, bool bExtra, bool bRecursive)
|
|
{
|
|
if(!pForm || !pFxVal || !pFxVal->IsObject())
|
|
return;
|
|
|
|
scaleformExtend::CommonItemData(pFxVal, pForm);
|
|
if(bExtra) {
|
|
scaleformExtend::StandardItemData(pFxVal, pForm);
|
|
scaleformExtend::MagicItemData(pFxVal, movieView, pForm, bExtra, bRecursive);
|
|
scaleformExtend::ActorData(pFxVal, movieView, pForm, bExtra, bRecursive);
|
|
scaleformExtend::MiscData(pFxVal, movieView, pForm, bExtra, bRecursive);
|
|
}
|
|
scaleformExtend::FormListData(pFxVal, movieView, pForm, bExtra, bRecursive);
|
|
}
|
|
|
|
void InventoryData(GFxValue * pFxVal, GFxMovieView * movieView, InventoryEntryData * objDesc)
|
|
{
|
|
TESForm * pForm = objDesc->type;
|
|
|
|
if(!pForm || !pFxVal || !pFxVal->IsObject())
|
|
return;
|
|
|
|
PlayerCharacter * pPC = *g_thePlayer;
|
|
|
|
BGSKeywordForm * keywords = DYNAMIC_CAST(pForm, TESForm, BGSKeywordForm);
|
|
if(keywords)
|
|
RegisterKeywords(pFxVal, movieView, keywords);
|
|
|
|
switch(pForm->GetFormType())
|
|
{
|
|
case kFormType_Armor:
|
|
{
|
|
TESObjectARMO * pArmor = DYNAMIC_CAST(pForm, TESForm, TESObjectARMO);
|
|
if(pArmor)
|
|
{
|
|
double armorValue = CALL_MEMBER_FN(pPC, GetArmorValue)(objDesc);
|
|
armorValue = round(armorValue);
|
|
RegisterNumber(pFxVal, "armor", armorValue);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kFormType_Weapon:
|
|
{
|
|
TESObjectWEAP * pWeapon = DYNAMIC_CAST(pForm, TESForm, TESObjectWEAP);
|
|
if(pWeapon)
|
|
{
|
|
double damage = CALL_MEMBER_FN(pPC, GetDamage)(objDesc);
|
|
damage = round(damage);
|
|
RegisterNumber(pFxVal, "damage", damage);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case kFormType_Ammo:
|
|
{
|
|
TESAmmo * pAmmo = DYNAMIC_CAST(pForm, TESForm, TESAmmo);
|
|
if(pAmmo)
|
|
{
|
|
double damage = CALL_MEMBER_FN(pPC, GetDamage)(objDesc);
|
|
damage = round(damage);
|
|
RegisterNumber(pFxVal, "damage", damage);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// SkyUI currently uses the itemcard info in ItemMenus to retrieve this data.
|
|
// This should replace the hack in future menus.
|
|
void ItemInfoData(GFxValue* pFxVal, InventoryEntryData * pEntry)
|
|
{
|
|
if(!pFxVal || !pEntry || !pFxVal->IsObject())
|
|
return;
|
|
|
|
RegisterNumber(pFxVal, "value", (double)CALL_MEMBER_FN(pEntry,GetValue)());
|
|
RegisterNumber(pFxVal, "weight", GetFormWeight(pEntry->type));
|
|
RegisterNumber(pFxVal, "isStolen", ! CALL_MEMBER_FN(pEntry,IsOwnedBy)(*g_thePlayer, 1));
|
|
}
|
|
|
|
void CraftDisenchantData(GFxValue * pFxVal, GFxMovieView * movieView, InventoryEntryData * pEntry)
|
|
{
|
|
if(!pEntry || !pEntry->type || !pFxVal || !pFxVal->IsObject())
|
|
return;
|
|
|
|
EnchantmentItem* enchantment = NULL;
|
|
|
|
TESEnchantableForm * enchantable = DYNAMIC_CAST(pEntry->type, TESForm, TESEnchantableForm);
|
|
if (enchantable && enchantable->enchantment)
|
|
{
|
|
enchantment = enchantable->enchantment;
|
|
}
|
|
else if (pEntry->extendDataList)
|
|
{
|
|
for (ExtendDataList::Iterator it = pEntry->extendDataList->Begin(); !it.End(); ++it)
|
|
{
|
|
BaseExtraList * pExtraDataList = it.Get();
|
|
|
|
if (pExtraDataList)
|
|
{
|
|
ExtraEnchantment* extraEnchant = static_cast<ExtraEnchantment*>(pExtraDataList->GetByType(kExtraData_Enchantment));
|
|
if (extraEnchant)
|
|
{
|
|
enchantment = extraEnchant->enchant;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (enchantment)
|
|
{
|
|
RegisterUnmanagedString(pFxVal, "effectName", enchantment->fullName.name.data);
|
|
}
|
|
}
|
|
|
|
enum
|
|
{
|
|
kCustomAlchemyFlag_None = 0x0,
|
|
kCustomAlchemyFlag_Any = 0x1,
|
|
kCustomAlchemyFlag_Beneficial = 0x2,
|
|
kCustomAlchemyFlag_Harmful = 0x4,
|
|
kCustomAlchemyFlag_Other = 0x8
|
|
};
|
|
|
|
void AlchemyCategoryArgs(AlchemyEffectCategory* effectArray, GFxValue * args, UInt32 numArgs)
|
|
{
|
|
AlchemyEffectCategory* curEffect = effectArray;
|
|
|
|
// Replace the "flag" value (at offset 1) with a new value.
|
|
// Previously, flag was just an incrementing number 1 to N+1, no special cases.
|
|
// We can easily calculate this number in AS, so flag can be used for other things.
|
|
|
|
const UInt32 kStride = 3;
|
|
const UInt32 kFlagOffset = 1;
|
|
|
|
// Start at kStride, because [0 .. kStride-1] is the "INGREDIENTS" entry
|
|
for (UInt32 i=kStride + kFlagOffset; i<numArgs; i+=kStride)
|
|
{
|
|
TESForm* form = LookupFormByID(curEffect->formId);
|
|
|
|
UInt32 newFlag = kCustomAlchemyFlag_None;
|
|
|
|
EffectSetting * effect = DYNAMIC_CAST(form, TESForm, EffectSetting);
|
|
if (effect)
|
|
{
|
|
UInt32 archetype = effect->properties.archetype;
|
|
UInt32 bDetrimental = (effect->properties.flags & EffectSetting::Properties::kEffectType_Detrimental) != 0;
|
|
|
|
switch (archetype)
|
|
{
|
|
case EffectSetting::Properties::kArchetype_ValueMod:
|
|
case EffectSetting::Properties::kArchetype_DualValueMod:
|
|
case EffectSetting::Properties::kArchetype_PeakValueMod:
|
|
{
|
|
newFlag = bDetrimental ? kCustomAlchemyFlag_Harmful : kCustomAlchemyFlag_Beneficial;
|
|
break;
|
|
}
|
|
case EffectSetting::Properties::kArchetype_Absorb:
|
|
case EffectSetting::Properties::kArchetype_CureDisease:
|
|
case EffectSetting::Properties::kArchetype_Invisibility:
|
|
case EffectSetting::Properties::kArchetype_CureParalysis:
|
|
case EffectSetting::Properties::kArchetype_CureAddiction:
|
|
case EffectSetting::Properties::kArchetype_CurePoison:
|
|
case EffectSetting::Properties::kArchetype_Dispel:
|
|
{
|
|
newFlag = kCustomAlchemyFlag_Beneficial;
|
|
break;
|
|
}
|
|
case EffectSetting::Properties::kArchetype_Frenzy:
|
|
case EffectSetting::Properties::kArchetype_Calm:
|
|
case EffectSetting::Properties::kArchetype_Demoralize:
|
|
case EffectSetting::Properties::kArchetype_Paralysis:
|
|
{
|
|
newFlag = kCustomAlchemyFlag_Harmful;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
newFlag = kCustomAlchemyFlag_Other;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
args[i].SetNumber(newFlag);
|
|
|
|
curEffect++;
|
|
}
|
|
}
|
|
}
|