[7901] Refactoting pet action bar related code. Fixed some related bugs.

* Correctly update action bar at loading and other cases when listed unlearned/not existed spells
* Avoid send data by PetSpellInitialize() many times while pet loading
This commit is contained in:
VladimirMangos 2009-05-27 19:24:12 +04:00
parent 1abe4c0d79
commit 4d8adefe70
7 changed files with 175 additions and 122 deletions

View file

@ -240,23 +240,11 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool
if (!is_temporary_summoned) if (!is_temporary_summoned)
{ {
// permanent controlled pets store state in DB if(!m_charmInfo->LoadActionBar(fields[14].GetCppString()))
Tokens tokens = StrSplit(fields[14].GetString(), " ");
if (tokens.size() != 20)
{ {
delete result; delete result;
return false; return false;
} }
int index;
Tokens::iterator iter;
for(iter = tokens.begin(), index = 0; index < 10; ++iter, ++index )
{
m_charmInfo->GetActionBarEntry(index)->Type = atol((*iter).c_str());
++iter;
m_charmInfo->GetActionBarEntry(index)->SpellOrAction = atol((*iter).c_str());
}
} }
// since last save (in seconds) // since last save (in seconds)
@ -299,6 +287,10 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool
// Spells should be loaded after pet is added to map, because in CheckCast is check on it // Spells should be loaded after pet is added to map, because in CheckCast is check on it
_LoadSpells(); _LoadSpells();
InitLevelupSpellsForLevel();
CleanupActionBar(); // remove unknown spells from action bar after load
_LoadSpellCooldowns(); _LoadSpellCooldowns();
owner->SetPet(this); // in DB stored only full controlled creature owner->SetPet(this); // in DB stored only full controlled creature
@ -329,8 +321,6 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool
} }
} }
InitLevelupSpellsForLevel();
m_loading = false; m_loading = false;
SynchronizeLevelWithOwner(); SynchronizeLevelWithOwner();
@ -421,8 +411,12 @@ void Pet::SavePetToDB(PetSaveMode mode)
<< curmana << ", " << curmana << ", "
<< GetPower(POWER_HAPPINESS) << ", '"; << GetPower(POWER_HAPPINESS) << ", '";
for(uint32 i = 0; i < 10; ++i) for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " " << uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " "; {
ss << uint32(m_charmInfo->GetActionBarEntry(i)->Type) << " "
<< uint32(m_charmInfo->GetActionBarEntry(i)->SpellOrAction) << " ";
};
ss << "', " ss << "', "
<< time(NULL) << ", " << time(NULL) << ", "
<< uint32(m_resetTalentsCost) << ", " << uint32(m_resetTalentsCost) << ", "
@ -1337,7 +1331,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel
// skip unknown ranks // skip unknown ranks
if(!HasSpell(rankSpellId)) if(!HasSpell(rankSpellId))
continue; continue;
removeSpell(rankSpellId,false); removeSpell(rankSpellId,false,false);
} }
} }
} }
@ -1358,7 +1352,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel
ToggleAutocast(itr2->first, false); ToggleAutocast(itr2->first, false);
oldspell_id = itr2->first; oldspell_id = itr2->first;
unlearnSpell(itr2->first,false); unlearnSpell(itr2->first,false,false);
break; break;
} }
// ignore new lesser rank // ignore new lesser rank
@ -1373,7 +1367,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel
if (IsPassiveSpell(spell_id)) if (IsPassiveSpell(spell_id))
CastSpell(this, spell_id, true); CastSpell(this, spell_id, true);
else else
m_charmInfo->AddSpellToAB(oldspell_id, spell_id); m_charmInfo->AddSpellToActionBar(spell_id);
if(newspell.active == ACT_ENABLED) if(newspell.active == ACT_ENABLED)
ToggleAutocast(spell_id, true); ToggleAutocast(spell_id, true);
@ -1396,16 +1390,17 @@ bool Pet::learnSpell(uint32 spell_id)
if (!addSpell(spell_id)) if (!addSpell(spell_id))
return false; return false;
Unit* owner = GetOwner(); if(!m_loading)
if(owner && owner->GetTypeId() == TYPEID_PLAYER)
{ {
if(!m_loading) Unit* owner = GetOwner();
if(owner && owner->GetTypeId() == TYPEID_PLAYER)
{ {
WorldPacket data(SMSG_PET_LEARNED_SPELL, 2); WorldPacket data(SMSG_PET_LEARNED_SPELL, 2);
data << uint16(spell_id); data << uint16(spell_id);
((Player*)owner)->GetSession()->SendPacket(&data); ((Player*)owner)->GetSession()->SendPacket(&data);
((Player*)owner)->PetSpellInitialize();
} }
((Player*)owner)->PetSpellInitialize();
} }
return true; return true;
} }
@ -1441,7 +1436,7 @@ void Pet::InitLevelupSpellsForLevel()
// will called first if level down // will called first if level down
if(spellEntry->spellLevel > level) if(spellEntry->spellLevel > level)
unlearnSpell(spellEntry->Id,false); unlearnSpell(spellEntry->Id,true);
// will called if level up // will called if level up
else else
learnSpell(spellEntry->Id); learnSpell(spellEntry->Id);
@ -1449,9 +1444,9 @@ void Pet::InitLevelupSpellsForLevel()
} }
} }
bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev) bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
{ {
if(removeSpell(spell_id,learn_prev)) if(removeSpell(spell_id,learn_prev,clear_ab))
{ {
if(GetOwner()->GetTypeId() == TYPEID_PLAYER) if(GetOwner()->GetTypeId() == TYPEID_PLAYER)
{ {
@ -1467,7 +1462,7 @@ bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev)
return false; return false;
} }
bool Pet::removeSpell(uint32 spell_id, bool learn_prev) bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
{ {
PetSpellMap::iterator itr = m_spells.find(spell_id); PetSpellMap::iterator itr = m_spells.find(spell_id);
if (itr == m_spells.end()) if (itr == m_spells.end())
@ -1498,29 +1493,35 @@ bool Pet::removeSpell(uint32 spell_id, bool learn_prev)
if (learn_prev) if (learn_prev)
{ {
if (uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id)) if (uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id))
{
// replace to next spell
if(!talentCost && !IsPassiveSpell(prev_id))
m_charmInfo->AddSpellToAB(spell_id, prev_id);
learnSpell(prev_id); learnSpell(prev_id);
}
else else
learn_prev = false; learn_prev = false;
} }
// if remove last rank or non-ranked then update action bar at server and client if need // if remove last rank or non-ranked then update action bar at server and client if need
if(!learn_prev && m_charmInfo->AddSpellToAB(spell_id, 0)) if (clear_ab && !learn_prev && m_charmInfo->RemoveSpellFromActionBar(spell_id))
{ {
// need update action bar for last removed rank if(!m_loading)
if (Unit* owner = GetOwner()) {
if (owner->GetTypeId() == TYPEID_PLAYER) // need update action bar for last removed rank
((Player*)owner)->PetSpellInitialize(); if (Unit* owner = GetOwner())
if (owner->GetTypeId() == TYPEID_PLAYER)
((Player*)owner)->PetSpellInitialize();
}
} }
return true; return true;
} }
void Pet::CleanupActionBar()
{
for(int i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
if(UnitActionBarEntry const* ab = m_charmInfo->GetActionBarEntry(i))
if(ab->SpellOrAction && ab->IsActionBarForSpell() && !HasSpell(ab->SpellOrAction))
m_charmInfo->SetActionBar(i,0,ACT_DISABLED);
}
void Pet::InitPetCreateSpells() void Pet::InitPetCreateSpells()
{ {
m_charmInfo->InitPetActionBar(); m_charmInfo->InitPetActionBar();

View file

@ -198,8 +198,9 @@ class Pet : public Creature
bool learnSpell(uint32 spell_id); bool learnSpell(uint32 spell_id);
void learnSpellHighRank(uint32 spellid); void learnSpellHighRank(uint32 spellid);
void InitLevelupSpellsForLevel(); void InitLevelupSpellsForLevel();
bool unlearnSpell(uint32 spell_id, bool learn_prev); bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
bool removeSpell(uint32 spell_id, bool learn_prev); bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab = true);
void CleanupActionBar();
PetSpellMap m_spells; PetSpellMap m_spells;
AutoSpellList m_autospells; AutoSpellList m_autospells;
@ -248,4 +249,4 @@ class Pet : public Creature
assert(false); assert(false);
} }
}; };
#endif #endif

View file

@ -357,7 +357,11 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, act_state); sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, act_state);
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add //ignore invalid position
if(position >= MAX_UNIT_ACTION_BAR_INDEX)
return;
//if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id)))
{ {
//sign for autocast //sign for autocast
@ -377,8 +381,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
((Pet*)pet)->ToggleAutocast(spell_id, false); ((Pet*)pet)->ToggleAutocast(spell_id, false);
} }
charmInfo->GetActionBarEntry(position)->Type = act_state; charmInfo->SetActionBar(position,spell_id,ActiveStates(act_state));
charmInfo->GetActionBarEntry(position)->SpellOrAction = spell_id;
} }
} }
} }
@ -560,11 +563,7 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )
else else
((Pet*)pet)->ToggleAutocast(spellid, state); ((Pet*)pet)->ToggleAutocast(spellid, state);
for(uint8 i = 0; i < 10; ++i) charmInfo->SetSpellAutocast(spellid,state);
{
if((charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED) && spellid == charmInfo->GetActionBarEntry(i)->SpellOrAction)
charmInfo->GetActionBarEntry(i)->Type = state ? ACT_ENABLED : ACT_DISABLED;
}
} }
void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket )

View file

@ -16410,10 +16410,7 @@ void Player::PetSpellInitialize()
data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0); data << uint8(charmInfo->GetReactState()) << uint8(charmInfo->GetCommandState()) << uint16(0);
// action bar loop // action bar loop
for(uint32 i = 0; i < 10; ++i) charmInfo->BuildActionBar(&data);
{
data << uint32(charmInfo->GetActionBarEntry(i)->Raw);
}
size_t spellsCountPos = data.wpos(); size_t spellsCountPos = data.wpos();
@ -16489,10 +16486,7 @@ void Player::PossessSpellInitialize()
data << uint32(0); data << uint32(0);
data << uint32(0); data << uint32(0);
for(uint32 i = 0; i < 10; ++i) //40 charmInfo->BuildActionBar(&data); //40
{
data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type);
}
data << uint8(addlist); //1 data << uint8(addlist); //1
@ -16543,10 +16537,7 @@ void Player::CharmSpellInitialize()
data << uint8(0) << uint8(0); data << uint8(0) << uint8(0);
data << uint16(0); data << uint16(0);
for(uint32 i = 0; i < 10; ++i) //40 charmInfo->BuildActionBar(&data); //40
{
data << uint16(charmInfo->GetActionBarEntry(i)->SpellOrAction) << uint16(charmInfo->GetActionBarEntry(i)->Type);
}
data << uint8(addlist); //1 data << uint8(addlist); //1

View file

@ -10328,28 +10328,18 @@ void CharmInfo::InitPetActionBar()
// the first 3 SpellOrActions are attack, follow and stay // the first 3 SpellOrActions are attack, follow and stay
for(uint32 i = 0; i < 3; ++i) for(uint32 i = 0; i < 3; ++i)
{ {
PetActionBar[i].Type = ACT_COMMAND; SetActionBar(i,COMMAND_ATTACK - i,ACT_COMMAND);
PetActionBar[i].SpellOrAction = COMMAND_ATTACK - i; SetActionBar(i + 7,COMMAND_ATTACK - i,ACT_REACTION);
PetActionBar[i + 7].Type = ACT_REACTION;
PetActionBar[i + 7].SpellOrAction = COMMAND_ATTACK - i;
}
for(uint32 i=0; i < 4; ++i)
{
PetActionBar[i + 3].Type = ACT_DISABLED;
PetActionBar[i + 3].SpellOrAction = 0;
} }
for(uint32 i = 0; i < 4; ++i)
SetActionBar(i,0,ACT_DISABLED);
} }
void CharmInfo::InitEmptyActionBar() void CharmInfo::InitEmptyActionBar()
{ {
for(uint32 x = 1; x < 10; ++x) SetActionBar(0,COMMAND_ATTACK,ACT_COMMAND);
{ for(uint32 x = 1; x < MAX_UNIT_ACTION_BAR_INDEX; ++x)
PetActionBar[x].Type = ACT_PASSIVE; SetActionBar(x,0,ACT_PASSIVE);
PetActionBar[x].SpellOrAction = 0;
}
PetActionBar[0].Type = ACT_COMMAND;
PetActionBar[0].SpellOrAction = COMMAND_ATTACK;
} }
void CharmInfo::InitPossessCreateSpells() void CharmInfo::InitPossessCreateSpells()
@ -10364,7 +10354,7 @@ void CharmInfo::InitPossessCreateSpells()
if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x])) if (IsPassiveSpell(((Creature*)m_unit)->m_spells[x]))
m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true); m_unit->CastSpell(m_unit, ((Creature*)m_unit)->m_spells[x], true);
else else
AddSpellToAB(0, ((Creature*)m_unit)->m_spells[x], ACT_PASSIVE); AddSpellToActionBar(((Creature*)m_unit)->m_spells[x], ACT_PASSIVE);
} }
} }
@ -10409,39 +10399,56 @@ void CharmInfo::InitCharmCreateSpells()
else else
newstate = ACT_PASSIVE; newstate = ACT_PASSIVE;
AddSpellToAB(0, spellId, newstate); AddSpellToActionBar(spellId, newstate);
} }
} }
} }
bool CharmInfo::AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate) bool CharmInfo::AddSpellToActionBar(uint32 spell_id, ActiveStates newstate)
{ {
// new spell already listed for example in case prepered switch to lesser rank in Pet::removeSpell uint32 first_id = spellmgr.GetFirstSpellInChain(spell_id);
for(uint8 i = 0; i < 10; ++i)
if (PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_PASSIVE)
if (newid && PetActionBar[i].SpellOrAction == newid)
return true;
// old spell can be leasted for example in case learn high rank // new spell rank can be already listed
for(uint8 i = 0; i < 10; ++i) for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{ {
if (PetActionBar[i].Type == ACT_DISABLED || PetActionBar[i].Type == ACT_ENABLED || PetActionBar[i].Type == ACT_PASSIVE) if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
{ {
if (PetActionBar[i].SpellOrAction == oldid) if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id)
{ {
PetActionBar[i].SpellOrAction = newid; PetActionBar[i].SpellOrAction = spell_id;
if (!oldid)
{
if (newstate == ACT_DECIDE)
PetActionBar[i].Type = ACT_DISABLED;
else
PetActionBar[i].Type = newstate;
}
return true; return true;
} }
} }
} }
// or use empty slot in other case
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
if (!PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
{
SetActionBar(i,spell_id,newstate == ACT_DECIDE ? ACT_DISABLED : newstate);
return true;
}
}
return false;
}
bool CharmInfo::RemoveSpellFromActionBar(uint32 spell_id)
{
uint32 first_id = spellmgr.GetFirstSpellInChain(spell_id);
for(uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
if (PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
{
if (spellmgr.GetFirstSpellInChain(PetActionBar[i].SpellOrAction) == first_id)
{
SetActionBar(i,0,ACT_DISABLED);
return true;
}
}
}
return false; return false;
} }
@ -10468,6 +10475,50 @@ void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0); m_unit->SetUInt32Value(UNIT_FIELD_PETNUMBER, 0);
} }
bool CharmInfo::LoadActionBar( std::string data )
{
Tokens tokens = StrSplit(data, " ");
if (tokens.size() != MAX_UNIT_ACTION_BAR_INDEX*2)
return false;
int index;
Tokens::iterator iter;
for(iter = tokens.begin(), index = 0; index < MAX_UNIT_ACTION_BAR_INDEX; ++iter, ++index )
{
// use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion
PetActionBar[index].Type = atol((*iter).c_str());
++iter;
PetActionBar[index].SpellOrAction = atol((*iter).c_str());
// check correctness
if(PetActionBar[index].IsActionBarForSpell() && !sSpellStore.LookupEntry(PetActionBar[index].SpellOrAction))
SetActionBar(index,0,ACT_DISABLED);
}
return true;
}
void CharmInfo::BuildActionBar( WorldPacket* data )
{
for(uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
*data << uint16(PetActionBar[i].SpellOrAction);
*data << uint16(PetActionBar[i].Type);
}
}
void CharmInfo::SetSpellAutocast( uint32 spell_id, bool state )
{
for(int i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
{
if(spell_id == PetActionBar[i].SpellOrAction && PetActionBar[i].IsActionBarForSpell())
{
PetActionBar[i].Type = state ? ACT_ENABLED : ACT_DISABLED;
break;
}
}
}
bool Unit::isFrozen() const bool Unit::isFrozen() const
{ {
return HasAuraState(AURA_STATE_FROZEN); return HasAuraState(AURA_STATE_FROZEN);

View file

@ -678,24 +678,6 @@ struct SpellNonMeleeDamage{
uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition); uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition);
struct UnitActionBarEntry
{
UnitActionBarEntry() : Raw(0) {}
union
{
struct
{
uint16 SpellOrAction;
uint16 Type;
};
struct
{
uint32 Raw;
};
};
};
#define MAX_DECLINED_NAME_CASES 5 #define MAX_DECLINED_NAME_CASES 5
struct DeclinedName struct DeclinedName
@ -738,12 +720,28 @@ enum CommandStates
COMMAND_ABANDON = 3 COMMAND_ABANDON = 3
}; };
struct UnitActionBarEntry
{
UnitActionBarEntry() : SpellOrAction(0), Type(ACT_DISABLED) {}
uint16 SpellOrAction;
uint16 Type;
// helper
bool IsActionBarForSpell() const
{
return Type == ACT_DISABLED || Type == ACT_ENABLED || Type == ACT_PASSIVE;
}
};
struct CharmSpellEntry struct CharmSpellEntry
{ {
uint16 spellId; uint16 spellId;
uint16 active; uint16 active;
}; };
#define MAX_UNIT_ACTION_BAR_INDEX 10
struct CharmInfo struct CharmInfo
{ {
public: public:
@ -762,15 +760,27 @@ struct CharmInfo
void InitCharmCreateSpells(); void InitCharmCreateSpells();
void InitPetActionBar(); void InitPetActionBar();
void InitEmptyActionBar(); void InitEmptyActionBar();
//return true if successful //return true if successful
bool AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate = ACT_DECIDE); bool AddSpellToActionBar(uint32 spellid, ActiveStates newstate = ACT_DECIDE);
bool RemoveSpellFromActionBar(uint32 spell_id);
bool LoadActionBar(std::string data);
void BuildActionBar(WorldPacket* data);
void SetSpellAutocast(uint32 spell_id, bool state);
void SetActionBar(uint8 index, uint32 spellOrAction,ActiveStates type)
{
PetActionBar[index].Type = type;
PetActionBar[index].SpellOrAction = spellOrAction;
}
UnitActionBarEntry const* GetActionBarEntry(uint8 index) const { return &(PetActionBar[index]); }
void ToggleCreatureAutocast(uint32 spellid, bool apply); void ToggleCreatureAutocast(uint32 spellid, bool apply);
UnitActionBarEntry* GetActionBarEntry(uint8 index) { return &(PetActionBar[index]); }
CharmSpellEntry* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); } CharmSpellEntry* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); }
private: private:
Unit* m_unit; Unit* m_unit;
UnitActionBarEntry PetActionBar[10]; UnitActionBarEntry PetActionBar[MAX_UNIT_ACTION_BAR_INDEX];
CharmSpellEntry m_charmspells[4]; CharmSpellEntry m_charmspells[4];
CommandStates m_CommandState; CommandStates m_CommandState;
ReactStates m_reactState; ReactStates m_reactState;

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "7900" #define REVISION_NR "7901"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__