aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2020-09-01 00:38:46 +0200
committerGitHub <noreply@github.com>2020-09-01 00:38:46 +0200
commit3fbbe7cfbe1bc51db12bdc1ec7b21c16d1716366 (patch)
treedfeb5042850efebde2c1ad79ca2db85f1da45d0f /src/server/game
parentb2895f31ec835e24d7e30944dc2fc8c5853e10dd (diff)
Core/Misc: DBC std::array refactors, and |Hachievement unit tests
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/Achievements/AchievementMgr.h2
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp2
-rw-r--r--src/server/game/Chat/HyperlinkTags.cpp11
-rw-r--r--src/server/game/DataStores/DBCStores.cpp4
-rw-r--r--src/server/game/DataStores/DBCStores.h2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp2
-rw-r--r--src/server/game/Spells/Spell.cpp6
-rw-r--r--src/server/game/Spells/SpellInfo.cpp76
-rw-r--r--src/server/game/Spells/SpellInfo.h22
9 files changed, 59 insertions, 68 deletions
diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h
index dd28bbd18a4..986b16aba6b 100644
--- a/src/server/game/Achievements/AchievementMgr.h
+++ b/src/server/game/Achievements/AchievementMgr.h
@@ -405,6 +405,8 @@ class TC_GAME_API AchievementGlobalMgr
AchievementRewards m_achievementRewards;
AchievementRewardLocales m_achievementRewardLocales;
+
+ friend class UnitTestDataLoader;
};
#define sAchievementMgr AchievementGlobalMgr::instance()
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index e80557e2383..93fcedf17bb 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -796,7 +796,7 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
// These are found in ItemRandomSuffix.dbc and ItemRandomProperties.dbc
// even though the DBC names seem misleading
- char* const* suffix = nullptr;
+ char const* const* suffix = nullptr;
if (propRefID < 0)
{
diff --git a/src/server/game/Chat/HyperlinkTags.cpp b/src/server/game/Chat/HyperlinkTags.cpp
index d9e4fb0aedb..d511265c537 100644
--- a/src/server/game/Chat/HyperlinkTags.cpp
+++ b/src/server/game/Chat/HyperlinkTags.cpp
@@ -58,13 +58,17 @@ class HyperlinkDataTokenizer
bool Trinity::Hyperlinks::LinkTags::achievement::StoreTo(AchievementLinkData& val, std::string_view text)
{
HyperlinkDataTokenizer t(text);
+
uint32 achievementId;
if (!t.TryConsumeTo(achievementId))
return false;
val.Achievement = sAchievementMgr->GetAchievement(achievementId);
- if (!(val.Achievement && t.TryConsumeTo(val.CharacterId) && t.TryConsumeTo(val.IsFinished) &&
- t.TryConsumeTo(val.Month) && t.TryConsumeTo(val.Day)))
+
+ if (!(val.Achievement && t.TryConsumeTo(val.CharacterId) && t.TryConsumeTo(val.IsFinished) && t.TryConsumeTo(val.Month) && t.TryConsumeTo(val.Day)))
return false;
+ if ((12 < val.Month) || (31 < val.Day))
+ return false;
+
int8 year;
if (!t.TryConsumeTo(year))
return false;
@@ -77,8 +81,7 @@ bool Trinity::Hyperlinks::LinkTags::achievement::StoreTo(AchievementLinkData& va
else
val.Year = 0;
- return (t.TryConsumeTo(val.Criteria[0]) &&
- t.TryConsumeTo(val.Criteria[1]) && t.TryConsumeTo(val.Criteria[2]) && t.TryConsumeTo(val.Criteria[3]) && t.IsEmpty());
+ return (t.TryConsumeTo(val.Criteria[0]) && t.TryConsumeTo(val.Criteria[1]) && t.TryConsumeTo(val.Criteria[2]) && t.TryConsumeTo(val.Criteria[3]) && t.IsEmpty());
}
bool Trinity::Hyperlinks::LinkTags::enchant::StoreTo(SpellInfo const*& val, std::string_view text)
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index d62d2c2b12f..eb6ca3c3a49 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -676,14 +676,14 @@ SimpleFactionsList const* GetFactionTeamList(uint32 faction)
return nullptr;
}
-char* GetPetName(uint32 petfamily, uint32 dbclang)
+char const* GetPetName(uint32 petfamily, uint32 dbclang)
{
if (!petfamily)
return nullptr;
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(petfamily);
if (!pet_family)
return nullptr;
- return pet_family->Name[dbclang]?pet_family->Name[dbclang]:nullptr;
+ return pet_family->Name[dbclang];
}
TalentSpellPos const* GetTalentSpellPos(uint32 spellId)
diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
index a273460f434..f3974d09307 100644
--- a/src/server/game/DataStores/DBCStores.h
+++ b/src/server/game/DataStores/DBCStores.h
@@ -36,7 +36,7 @@ enum LocaleConstant : uint8;
typedef std::list<uint32> SimpleFactionsList;
TC_GAME_API SimpleFactionsList const* GetFactionTeamList(uint32 faction);
-TC_GAME_API char* GetPetName(uint32 petfamily, uint32 dbclang);
+TC_GAME_API char const* GetPetName(uint32 petfamily, uint32 dbclang);
TC_GAME_API uint32 GetTalentSpellCost(uint32 spellId);
TC_GAME_API TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index c3d0cb0996f..8498e19dfc5 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -7869,7 +7869,7 @@ std::string ObjectMgr::GeneratePetName(uint32 entry)
if (!cinfo)
return std::string();
- char* petname = GetPetName(cinfo->family, sWorld->GetDefaultDbcLocale());
+ char const* petname = GetPetName(cinfo->family, sWorld->GetDefaultDbcLocale());
if (petname)
return std::string(petname);
else
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 6e57a17172f..3412310bce6 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -867,13 +867,14 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar
case TARGET_SELECT_CATEGORY_NEARBY:
case TARGET_SELECT_CATEGORY_CONE:
case TARGET_SELECT_CATEGORY_AREA:
+ {
// targets for effect already selected
if (effectMask & processedEffectMask)
return;
+ std::array<SpellEffectInfo, MAX_SPELL_EFFECTS> const& effects = GetSpellInfo()->Effects;
// choose which targets we can select at once
- for (uint32 j = effIndex + 1; j < MAX_SPELL_EFFECTS; ++j)
+ for (uint32 j = effIndex + 1; j < effects.size(); ++j)
{
- SpellEffectInfo const* effects = GetSpellInfo()->Effects;
if (effects[j].IsEffect() &&
effects[effIndex].TargetA.GetTarget() == effects[j].TargetA.GetTarget() &&
effects[effIndex].TargetB.GetTarget() == effects[j].TargetB.GetTarget() &&
@@ -886,6 +887,7 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar
}
processedEffectMask |= effectMask;
break;
+ }
default:
break;
}
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 60122176508..7bfb4593469 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -211,8 +211,8 @@ uint32 SpellImplicitTargetInfo::GetExplicitTargetMask(bool& srcSet, bool& dstSet
return targetMask;
}
-SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_TARGETS] =
-{
+std::array<SpellImplicitTargetInfo::StaticData, TOTAL_SPELL_TARGETS> SpellImplicitTargetInfo::_data =
+{ {
{TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, //
{TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 1 TARGET_UNIT_CASTER
{TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 2 TARGET_UNIT_NEARBY_ENEMY
@@ -324,7 +324,7 @@ SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_T
{TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 108 TARGET_GAMEOBJECT_CONE
{TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 109
{TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 110 TARGET_UNIT_CONE_ENTRY_110
-};
+} };
SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex)
{
@@ -595,8 +595,8 @@ SpellTargetObjectTypes SpellEffectInfo::GetUsedTargetObjectType() const
return _data[Effect].UsedTargetObjectType;
}
-SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] =
-{
+std::array<SpellEffectInfo::StaticData, TOTAL_SPELL_EFFECTS> SpellEffectInfo::_data =
+{ {
// implicit target type used target object type
{EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 0
{EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 1 SPELL_EFFECT_INSTAKILL
@@ -763,7 +763,7 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] =
{EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 162 SPELL_EFFECT_TALENT_SPEC_SELECT
{EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 163 SPELL_EFFECT_163
{EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 164 SPELL_EFFECT_REMOVE_AURA
-};
+} };
SpellInfo::SpellInfo(SpellEntry const* spellEntry)
{
@@ -819,33 +819,19 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry)
RangeEntry = spellEntry->RangeIndex ? sSpellRangeStore.LookupEntry(spellEntry->RangeIndex) : nullptr;
Speed = spellEntry->Speed;
StackAmount = spellEntry->CumulativeAura;
- for (uint8 i = 0; i < 2; ++i)
- Totem[i] = spellEntry->Totem[i];
-
- for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i)
- Reagent[i] = spellEntry->Reagent[i];
-
- for (uint8 i = 0; i < MAX_SPELL_REAGENTS; ++i)
- ReagentCount[i] = spellEntry->ReagentCount[i];
-
+ Totem = spellEntry->Totem;
+ Reagent = spellEntry->Reagent;
+ ReagentCount = spellEntry->ReagentCount;
EquippedItemClass = spellEntry->EquippedItemClass;
EquippedItemSubClassMask = spellEntry->EquippedItemSubclass;
EquippedItemInventoryTypeMask = spellEntry->EquippedItemInvTypes;
- for (uint8 i = 0; i < 2; ++i)
- TotemCategory[i] = spellEntry->RequiredTotemCategoryID[i];
-
- for (uint8 i = 0; i < 2; ++i)
- SpellVisual[i] = spellEntry->SpellVisualID[i];
-
+ TotemCategory = spellEntry->RequiredTotemCategoryID;
+ SpellVisual = spellEntry->SpellVisualID;
SpellIconID = spellEntry->SpellIconID;
ActiveIconID = spellEntry->ActiveIconID;
Priority = spellEntry->SpellPriority;
- for (uint8 i = 0; i < 16; ++i)
- SpellName[i] = spellEntry->Name[i];
-
- for (uint8 i = 0; i < 16; ++i)
- Rank[i] = spellEntry->NameSubtext[i];
-
+ SpellName = spellEntry->Name;
+ Rank = spellEntry->NameSubtext;
MaxTargetLevel = spellEntry->MaxTargetLevel;
MaxAffectedTargets = spellEntry->MaxTargets;
SpellFamilyName = spellEntry->SpellClassSet;
@@ -2856,9 +2842,9 @@ void SpellInfo::_LoadImmunityInfo()
void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool apply) const
{
- ImmunityInfo const* immuneInfo = _immunityInfo + effIndex;
+ ImmunityInfo const& immuneInfo = _immunityInfo[effIndex];
- if (uint32 schoolImmunity = immuneInfo->SchoolImmuneMask)
+ if (uint32 schoolImmunity = immuneInfo.SchoolImmuneMask)
{
target->ApplySpellImmune(Id, IMMUNITY_SCHOOL, schoolImmunity, apply);
@@ -2876,7 +2862,7 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool app
}
}
- if (uint32 mechanicImmunity = immuneInfo->MechanicImmuneMask)
+ if (uint32 mechanicImmunity = immuneInfo.MechanicImmuneMask)
{
for (uint32 i = 0; i < MAX_MECHANIC; ++i)
if (mechanicImmunity & (1 << i))
@@ -2886,7 +2872,7 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool app
target->RemoveAurasWithMechanic(mechanicImmunity, AURA_REMOVE_BY_DEFAULT, Id);
}
- if (uint32 dispelImmunity = immuneInfo->DispelImmune)
+ if (uint32 dispelImmunity = immuneInfo.DispelImmune)
{
target->ApplySpellImmune(Id, IMMUNITY_DISPEL, dispelImmunity, apply);
@@ -2903,17 +2889,17 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool app
}
}
- if (uint32 damageImmunity = immuneInfo->DamageSchoolMask)
+ if (uint32 damageImmunity = immuneInfo.DamageSchoolMask)
target->ApplySpellImmune(Id, IMMUNITY_DAMAGE, damageImmunity, apply);
- for (AuraType auraType : immuneInfo->AuraTypeImmune)
+ for (AuraType auraType : immuneInfo.AuraTypeImmune)
{
target->ApplySpellImmune(Id, IMMUNITY_STATE, auraType, apply);
if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
target->RemoveAurasByType(auraType);
}
- for (SpellEffects effectType : immuneInfo->SpellEffectImmune)
+ for (SpellEffects effectType : immuneInfo.SpellEffectImmune)
target->ApplySpellImmune(Id, IMMUNITY_EFFECT, effectType, apply);
}
@@ -2922,22 +2908,20 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf
if (!auraSpellInfo)
return false;
- for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ for (ImmunityInfo const& immuneInfo : _immunityInfo)
{
- ImmunityInfo const* immuneInfo = _immunityInfo + i;
-
if (!auraSpellInfo->HasAttribute(SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
{
- if (uint32 schoolImmunity = immuneInfo->SchoolImmuneMask)
+ if (uint32 schoolImmunity = immuneInfo.SchoolImmuneMask)
if ((auraSpellInfo->SchoolMask & schoolImmunity) != 0)
return true;
}
- if (uint32 mechanicImmunity = immuneInfo->MechanicImmuneMask)
+ if (uint32 mechanicImmunity = immuneInfo.MechanicImmuneMask)
if ((mechanicImmunity & (1 << auraSpellInfo->Mechanic)) != 0)
return true;
- if (uint32 dispelImmunity = immuneInfo->DispelImmune)
+ if (uint32 dispelImmunity = immuneInfo.DispelImmune)
if (auraSpellInfo->Dispel == dispelImmunity)
return true;
@@ -2948,8 +2932,8 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf
if (!effectName)
continue;
- auto spellImmuneItr = immuneInfo->SpellEffectImmune.find(static_cast<SpellEffects>(effectName));
- if (spellImmuneItr == immuneInfo->SpellEffectImmune.cend())
+ auto spellImmuneItr = immuneInfo.SpellEffectImmune.find(static_cast<SpellEffects>(effectName));
+ if (spellImmuneItr == immuneInfo.SpellEffectImmune.cend())
{
immuneToAllEffects = false;
break;
@@ -2957,7 +2941,7 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf
if (uint32 mechanic = auraSpellInfo->Effects[effIndex].Mechanic)
{
- if (!(immuneInfo->MechanicImmuneMask & (1 << mechanic)))
+ if (!(immuneInfo.MechanicImmuneMask & (1 << mechanic)))
{
immuneToAllEffects = false;
break;
@@ -2969,13 +2953,13 @@ bool SpellInfo::CanSpellProvideImmunityAgainstAura(SpellInfo const* auraSpellInf
if (uint32 auraName = auraSpellInfo->Effects[effIndex].ApplyAuraName)
{
bool isImmuneToAuraEffectApply = false;
- auto auraImmuneItr = immuneInfo->AuraTypeImmune.find(static_cast<AuraType>(auraName));
- if (auraImmuneItr != immuneInfo->AuraTypeImmune.cend())
+ auto auraImmuneItr = immuneInfo.AuraTypeImmune.find(static_cast<AuraType>(auraName));
+ if (auraImmuneItr != immuneInfo.AuraTypeImmune.cend())
isImmuneToAuraEffectApply = true;
if (!isImmuneToAuraEffectApply && !auraSpellInfo->IsPositiveEffect(effIndex) && !auraSpellInfo->HasAttribute(SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE))
{
- if (uint32 applyHarmfulAuraImmunityMask = immuneInfo->ApplyHarmfulAuraImmuneMask)
+ if (uint32 applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask)
if ((auraSpellInfo->GetSchoolMask() & applyHarmfulAuraImmunityMask) != 0)
isImmuneToAuraEffectApply = true;
}
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index c48e90cde61..e897b63cfe1 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -232,7 +232,7 @@ private:
SpellTargetCheckTypes SelectionCheckType; // defines selection criteria
SpellTargetDirectionTypes DirectionType; // direction for cone and dest targets
};
- static StaticData _data[TOTAL_SPELL_TARGETS];
+ static std::array<StaticData, TOTAL_SPELL_TARGETS> _data;
};
class TC_GAME_API SpellEffectInfo
@@ -296,7 +296,7 @@ private:
SpellEffectImplicitTargetTypes ImplicitTargetType; // defines what target can be added to effect target list if there's no valid target type provided for effect
SpellTargetObjectTypes UsedTargetObjectType; // defines valid target object type for spell effect
};
- static StaticData _data[TOTAL_SPELL_EFFECTS];
+ static std::array<StaticData, TOTAL_SPELL_EFFECTS> _data;
};
struct TC_GAME_API SpellDiminishInfo
@@ -376,19 +376,19 @@ class TC_GAME_API SpellInfo
SpellRangeEntry const* RangeEntry;
float Speed;
uint32 StackAmount;
- uint32 Totem[2];
- int32 Reagent[MAX_SPELL_REAGENTS];
- uint32 ReagentCount[MAX_SPELL_REAGENTS];
+ std::array<uint32, 2> Totem;
+ std::array<int32, MAX_SPELL_REAGENTS> Reagent;
+ std::array<uint32, MAX_SPELL_REAGENTS> ReagentCount;
int32 EquippedItemClass;
int32 EquippedItemSubClassMask;
int32 EquippedItemInventoryTypeMask;
- uint32 TotemCategory[2];
- uint32 SpellVisual[2];
+ std::array<uint32, 2> TotemCategory;
+ std::array<uint32, 2> SpellVisual;
uint32 SpellIconID;
uint32 ActiveIconID;
uint32 Priority;
- char* SpellName[16];
- char* Rank[16];
+ std::array<char const*, 16> SpellName;
+ std::array<char const*, 16> Rank;
uint32 MaxTargetLevel;
uint32 MaxAffectedTargets;
uint32 SpellFamilyName;
@@ -397,7 +397,7 @@ class TC_GAME_API SpellInfo
uint32 PreventionType;
int32 AreaGroupId;
uint32 SchoolMask;
- SpellEffectInfo Effects[MAX_SPELL_EFFECTS];
+ std::array<SpellEffectInfo, MAX_SPELL_EFFECTS> Effects;
uint32 ExplicitTargetMask;
SpellChainNode const* ChainEntry;
@@ -552,7 +552,7 @@ class TC_GAME_API SpellInfo
uint32 _allowedMechanicMask;
- ImmunityInfo _immunityInfo[MAX_SPELL_EFFECTS];
+ std::array<ImmunityInfo, MAX_SPELL_EFFECTS> _immunityInfo;
};
#endif // _SPELLINFO_H