|
|
 |
 |
 |
 |
|
 |
 |
|
 |
 |
|
 |
|
Development::Bug Reports Post detailed bug reports and what you would like to see next in the emu here. |

11-10-2008, 12:54 AM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Hmm, if "level = set_level;" is setting the character level, then what is "m_pp.level = set_level;" doing? Is that just for updating the BLOB? I don't get the difference. Sorry for my noobishness lol.
I know we generate the leveling message, but there is another message that shows up when you #level that tells you how many levels you gained or lost. I am not at home right now, so I can't check it, but that is the only thing I can think of that level_old could possibly be used for. Not that there is any good reason to remove it (if nothing is broken), but I am just trying to understand what is going on.
No big deal really though, as I am pretty sure we should have this bug cleared up. I will definitely try to get this in tonight and test it out.
|

11-10-2008, 01:00 AM
|
Administrator
|
|
Join Date: Sep 2006
Posts: 1,348
|
|
You have to understand how the objects work. m_pp basically is the player profile that's what we read back when we log in to get our bearings and what we save() to. But most the time the client/npc tracks it's own data without referencing the player profile. Without that line you wouldn't be that level for things like spell and combat calculations until you zoned because the active client object still thinks your level is the one it got from pp originally.
|

11-10-2008, 03:45 AM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Thanks again KLS. So, that is basically just sending a level update to the client. I understand much better now 
|
 |
|
 |

11-10-2008, 08:27 AM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Well, I got this tested, and had to adjust how it was written slightly to make sure it included the logging.
Code:
void Client::SetLevel(int8 set_level, bool command)
{
#ifdef GUILDWARS
if(set_level > SETLEVEL) {
Message(0,"You cannot exceed level %i on a GuildWars Server.",SETLEVEL);
return;
}
#endif
if (GetEXPForLevel(set_level) == 0xFFFFFFFF) {
LogFile->write(EQEMuLog::Error,"Client::SetLevel() GetEXPForLevel(%i) = 0xFFFFFFFF", set_level);
return;
}
EQApplicationPacket* outapp = new EQApplicationPacket(OP_LevelUpdate, sizeof(LevelUpdate_Struct));
LevelUpdate_Struct* lu = (LevelUpdate_Struct*)outapp->pBuffer;
lu->level = set_level;
lu->level_old = level;
level = set_level;
if(IsRaidGrouped())
{
Raid *r = this->GetRaid();
if(r){
r->UpdateLevel(GetName(), set_level);
}
}
if (set_level > m_pp.level2) {
m_pp.points += 5 * (set_level - m_pp.level2);
m_pp.level2 = set_level;
#ifdef EMBPERL
((PerlembParser*)parse)->Event(EVENT_LEVEL_UP, 0, "", (NPC*)NULL, this);
#endif
}
m_pp.level = set_level;
if (command){
m_pp.exp = GetEXPForLevel(set_level);
Message(15, "Welcome to level %i!", set_level);
lu->exp = 0;
}
else {
float tmpxp = (float) ( (float) m_pp.exp - GetEXPForLevel( GetLevel() )) /
( (float) GetEXPForLevel(GetLevel()+1) - GetEXPForLevel(GetLevel()));
lu->exp = (int32)(330.0f * tmpxp);
}
QueuePacket(outapp);
safe_delete(outapp);
this->SendAppearancePacket(AT_WhoLevel, set_level); // who level change
LogFile->write(EQEMuLog::Normal,"Setting Level for %s to %i", GetName(), set_level);
CalcBonuses();
if(!RuleB(Character, HealOnLevel))
{
int mhp = CalcMaxHP();
if(GetHP() > mhp)
SetHP(mhp);
}
else
{
SetHP(CalcMaxHP()); // Why not, lets give them a free heal
}
SendHPUpdate();
SetMana(CalcMaxMana());
UpdateWho();
Save();
}
But, it still doesn't seem to be working, so I am guessing that level2 is either being updated somewhere else to match current level, or the points are being added elsewhere.
|
 |
|
 |

11-10-2008, 09:18 AM
|
Developer
|
|
Join Date: Feb 2004
Location: UK
Posts: 1,540
|
|
You need to check if m_pp.level2 is zero, which it will be for any character created before this change, otherwise you will give existing characters lots of extra skill points. The code below works for me, however if you try and train skills after levelling, without zoning, the client will show an extra 5 points, however if you zone first, it seems to display correctly.
Code:
if(set_level > m_pp.level2)
{
printf("m_pp.level2 is %i\n", m_pp.level2); fflush(stdout);
if(m_pp.level2 == 0)
m_pp.points += 5;
else
m_pp.points += (5 * (set_level - m_pp.level2));
m_pp.level2 = set_level;
}
if(set_level > m_pp.level) { // Yes I am aware that you could delevel yourself and relevel this is just to test!
#ifdef EMBPERL
((PerlembParser*)parse)->Event(EVENT_LEVEL_UP, 0, "", (NPC*)NULL, this);
#endif
}
m_pp.level = set_level;
|
 |
|
 |

11-10-2008, 09:55 AM
|
Developer
|
|
Join Date: Feb 2004
Location: UK
Posts: 1,540
|
|
I've just had a look at the client disassembly and it is comparing lu->level with lu->level_old and adding 5 skill points if lu->level > lu_level_old, so in fact lu->level_old should be set to the max level the player has previously reached (m_pp.level2). This seems to work:
Code:
void Client::SetLevel(int8 set_level, bool command)
{
#ifdef GUILDWARS
if(set_level > SETLEVEL) {
Message(0,"You cannot exceed level %i on a GuildWars Server.",SETLEVEL);
return;
}
#endif
if (GetEXPForLevel(set_level) == 0xFFFFFFFF) {
LogFile->write(EQEMuLog::Error,"Client::SetLevel() GetEXPForLevel(%i) = 0xFFFFFFFF", set_level);
return;
}
EQApplicationPacket* outapp = new EQApplicationPacket(OP_LevelUpdate, sizeof(LevelUpdate_Struct));
LevelUpdate_Struct* lu = (LevelUpdate_Struct*)outapp->pBuffer;
lu->level = set_level;
if(m_pp.level2 != 0)
lu->level_old = m_pp.level2;
else
lu->level_old = level;
level = set_level;
if(IsRaidGrouped())
{
Raid *r = this->GetRaid();
if(r){
r->UpdateLevel(GetName(), set_level);
}
}
if(set_level > m_pp.level2)
{
if(m_pp.level2 == 0)
m_pp.points += 5;
else
m_pp.points += (5 * (set_level - m_pp.level2));
m_pp.level2 = set_level;
}
if(set_level > m_pp.level) { // Yes I am aware that you could delevel yourself and relevel this is just to test!
#ifdef EMBPERL
((PerlembParser*)parse)->Event(EVENT_LEVEL_UP, 0, "", (NPC*)NULL, this);
#endif
}
m_pp.level = set_level;
if (command){
m_pp.exp = GetEXPForLevel(set_level);
Message(15, "Welcome to level %i!", set_level);
lu->exp = 0;
}
else {
float tmpxp = (float) ( (float) m_pp.exp - GetEXPForLevel( GetLevel() )) /
( (float) GetEXPForLevel(GetLevel()+1) - GetEXPForLevel(GetLevel()));
lu->exp = (int32)(330.0f * tmpxp);
}
QueuePacket(outapp);
safe_delete(outapp);
this->SendAppearancePacket(AT_WhoLevel, set_level); // who level change
LogFile->write(EQEMuLog::Normal,"Setting Level for %s to %i", GetName(), set_level);
CalcBonuses();
if(!RuleB(Character, HealOnLevel))
{
int mhp = CalcMaxHP();
if(GetHP() > mhp)
SetHP(mhp);
}
else
{
SetHP(CalcMaxHP()); // Why not, lets give them a free heal
}
SendHPUpdate();
SetMana(CalcMaxMana());
UpdateWho();
Save();
}
|
 |
|
 |

11-10-2008, 10:24 AM
|
 |
Developer
|
|
Join Date: Aug 2006
Location: USA
Posts: 5,946
|
|
Nice work, Derision! So, basically, if I understand correctly, the packet structure should say level2 instead of level_old? Not that it actually requires it to say that for this to work, but in reality, I am thinking level_old is really level2. I think that would make everything match up perfectly and finally make actual sense of the level2 field.
I am going to test this now.
|
Thread Tools |
|
Display Modes |
Hybrid Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -4. The time now is 06:45 AM.
|
|
 |
|
 |
|
|
|
 |
|
 |
|
 |