Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Server Code Submissions

Reply
 
Thread Tools Display Modes
  #1  
Old 05-14-2011, 04:14 PM
Sikkun
Sarnak
 
Join Date: Apr 2011
Posts: 30
Default Mounted Out of Combat Regeneration

Hello,
I was unable to find a fix for this (sorry if there is a known one) so here is the code I added to enable Mounted OOC Like on live.

Orginal:
horse.cpp

Code:
void Client::SummonHorse(int16 spell_id) {
	if (GetHorseId() != 0) {
		Message(13,"You already have a Horse.  Get off, Fatbutt!");
		return;
	}
	if(!Horse::IsHorseSpell(spell_id)) {
		LogFile->write(EQEMuLog::Error, "%s tried to summon an unknown horse, spell id %d", GetName(), spell_id);
		return;
	}
	
	// No Horse, lets get them one.
	
	Horse* horse = new Horse(this, spell_id, GetX(), GetY(), GetZ(), GetHeading());
	
	//we want to manage the spawn packet ourself.
	//another reason is we dont want quests executing on it.
	entity_list.AddNPC(horse, false);
	
	// Okay, lets say they have a horse now.
	
	
	EQApplicationPacket outapp;
	horse->CreateHorseSpawnPacket(&outapp, GetName(), GetID());
/*	// Doodman: Kludged in here instead of adding a field to PCType. FIXME!
	NewSpawn_Struct* ns=(NewSpawn_Struct*)outapp->pBuffer;
	ns->spawn.texture=mount_color;
	ns->spawn.pet_owner_id=0;
	ns->spawn.walkspeed=npc_type->walkspeed;
	ns->spawn.runspeed=npc_type->runspeed;
*/
	entity_list.QueueClients(horse, &outapp);
	
	
	int16 tmpID = horse->GetID();
	SetHorseId(tID);
}
New: (one line at the end)

Code:
void Client::SummonHorse(int16 spell_id) {
	if (GetHorseId() != 0) {
		Message(13,"You already have a Horse.  Get off, Fatbutt!");
		return;
	}
	if(!Horse::IsHorseSpell(spell_id)) {
		LogFile->write(EQEMuLog::Error, "%s tried to summon an unknown horse, spell id %d", GetName(), spell_id);
		return;
	}
	
	// No Horse, lets get them one.
	
	Horse* horse = new Horse(this, spell_id, GetX(), GetY(), GetZ(), GetHeading());
	
	//we want to manage the spawn packet ourself.
	//another reason is we dont want quests executing on it.
	entity_list.AddNPC(horse, false);
	
	// Okay, lets say they have a horse now.
	
	
	EQApplicationPacket outapp;
	horse->CreateHorseSpawnPacket(&outapp, GetName(), GetID());
/*	// Doodman: Kludged in here instead of adding a field to PCType. FIXME!
	NewSpawn_Struct* ns=(NewSpawn_Struct*)outapp->pBuffer;
	ns->spawn.texture=mount_color;
	ns->spawn.pet_owner_id=0;
	ns->spawn.walkspeed=npc_type->walkspeed;
	ns->spawn.runspeed=npc_type->runspeed;
*/
	entity_list.QueueClients(horse, &outapp);
	
	
	int16 tmpID = horse->GetID();
	SetHorseId(tmpID);

	//Sets Player action to Sit
	playeraction = 1;

}
And to make the OOC stop when not mounted

Orginal:
Code:
void Client::SetHorseId(int16 horseid_in) {
	//if its the same, do nothing
	if(horseId == horseid_in)
		return;
	
	//otherwise it changed.
	//if we have a horse, get rid of it no matter what.
	if(horseId) {
		Mob *horse = entity_list.GetMob(horseId);
		if(horse != NULL)
		horse->Depop();
	}
	
	//now we take whatever they gave us.
	horseId = horseid_in;
}
New (just one line again)

Code:
void Client::SetHorseId(int16 horseid_in) {
	//if its the same, do nothing
	if(horseId == horseid_in)
		return;
	
	//otherwise it changed.
	//if we have a horse, get rid of it no matter what.
	if(horseId) {
		Mob *horse = entity_list.GetMob(horseId);
		if(horse != NULL)
		{
			horse->Depop();
                                         //Sets player action to stand
			playeraction = 0;
		}
	}
	
	//now we take whatever they gave us.
	horseId = horseid_in;
}
Sikkun
Reply With Quote
  #2  
Old 05-15-2011, 02:18 AM
Sikkun
Sarnak
 
Join Date: Apr 2011
Posts: 30
Default

So I did more testing with this and the only problem I can find with this solution is that you still gain rested OOC while moving on a mount.

If anyone could point out were the code for movement is im sure just adding a playeraction = 0 when movement would fix that.

Or another thought I can not find the code that controles the resting UI. If I knew were that was I see no reason why something like...

if(restui == true)
{
playeraction = 1;
}
else
playeraction = 2

wouldn't fix the entire mounted ooc problem

Sikkun
Reply With Quote
  #3  
Old 05-15-2011, 03:46 PM
Sikkun
Sarnak
 
Join Date: Apr 2011
Posts: 30
Default

Ok so I have came out with a new solution. This works when sitting and standing still on a mount, it no longer allows you to regenerate while moving on a mount.

in the Zone project
client_process.cpp
void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
Method

ADD:
Code:
//allow player to have OOC regeneration on a mount
	if(ppu->y_pos == y_pos || ppu->x_pos == x_pos)
	{
		if(GetHorseId() != 0)
		{
			playeraction = 1;
		}
	}
	else if(ppu->y_pos != y_pos || ppu->x_pos != x_pos)
	{
		if(GetHorseId() != 0)
		{
			playeraction = 0;
		}
	}
I added my code right after the //Break hide if moving without sneak code block so it looks like:

Code:
// Break Hide if moving without sneaking and set rewind timer if moved
	if(ppu->y_pos != y_pos || ppu->x_pos != x_pos){
	    if((hidden || improved_hidden) && !sneaking){
			hidden = false;
			improved_hidden = false;
			if(!invisible) {
				EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct));
				SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer;
				sa_out->spawn_id = GetID();
				sa_out->type = 0x03;
				sa_out->parameter = 0;
				entity_list.QueueClients(this, outapp, true);
				safe_delete(outapp);
			}
		}
		rewind_timer.Start(30000, true);
	}

	//allow player to have OOC regeneration on a mount
	if(ppu->y_pos == y_pos || ppu->x_pos == x_pos)
	{
		if(GetHorseId() != 0)
		{
			playeraction = 1;
		}
	}
	else if(ppu->y_pos != y_pos || ppu->x_pos != x_pos)
	{
		if(GetHorseId() != 0)
		{
			playeraction = 0;
		}
	}
Reply With Quote
  #4  
Old 05-16-2011, 04:20 PM
Sikkun
Sarnak
 
Join Date: Apr 2011
Posts: 30
Default

Make client_process.cpp
client_packet.cpp
Reply With Quote
  #5  
Old 05-16-2011, 05:09 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,743
Default

Hmm, forcing them to sitting seems like the wrong approach to me. You know they're on a horse, so I think something like this might be better. I haven't tested it, but I think the logic is correct. It works the same as mana regen when sitting or mounted as seen in Client::CalcManaRegen() and Client::CalcBaseManaRegen().

client_process.cpp
Code:
void Client::CalcRestState() {

	// This method calculates rest state HP and mana regeneration.
	// The client must have been out of combat for RuleI(Character, RestRegenTimeToActivate) seconds,
	// must be sitting down or mounted, and must not have any detrimental spells affecting them.
	//
	if(!RuleI(Character, RestRegenPercent))
		return;

	RestRegenHP = RestRegenMana = RestRegenEndurance = 0;

        if(AggroCount || !IsSitting() || !GetHorseId())
		return;
Reply With Quote
  #6  
Old 05-16-2011, 10:30 PM
ChaosSlayerZ's Avatar
ChaosSlayerZ
Demi-God
 
Join Date: Mar 2009
Location: Umm
Posts: 1,492
Default

important note when implementing this new thing, there is a Rule in DB which controls OOC regen, if its on, off and how it scales. don't forget to take it into account
Reply With Quote
  #7  
Old 05-16-2011, 10:50 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,743
Default

Quote:
Originally Posted by ChaosSlayerZ View Post
important note when implementing this new thing, there is a Rule in DB which controls OOC regen, if its on, off and how it scales. don't forget to take it into account
All my change does is extend how it normally works to include people on a horse. The rule is observed, no formulas change, and all scaling stays the same.
Reply With Quote
  #8  
Old 05-17-2011, 10:06 AM
Sikkun
Sarnak
 
Join Date: Apr 2011
Posts: 30
Default

My code doesn't actually force the user to sit it just tells the system you are sitting (same animations as usual). Though ill try your code to see if that's an easier fix.
Reply With Quote
  #9  
Old 05-17-2011, 10:53 AM
sorvani
Dragon
 
Join Date: May 2010
Posts: 966
Default

Quote:
Originally Posted by lerxst2112 View Post
client_process.cpp
Code:
void Client::CalcRestState() {

	// This method calculates rest state HP and mana regeneration.
	// The client must have been out of combat for RuleI(Character, RestRegenTimeToActivate) seconds,
	// must be sitting down or mounted, and must not have any detrimental spells affecting them.
	//
	if(!RuleI(Character, RestRegenPercent))
		return;

	RestRegenHP = RestRegenMana = RestRegenEndurance = 0;

        if(AggroCount || !IsSitting() || !GetHorseId())
		return;
IsSitting will be FALSE if GetHorseID = TRUE so the ! will cause it to still do what it was doing before, return if you are not sitting. Should it be more like:
Code:
        if(AggroCount || !(IsSitting() || GetHorseId()) )
Reply With Quote
  #10  
Old 05-17-2011, 11:28 AM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,743
Default

You're probably right on the logic. I didn't test it, but I think if a change is made, it should be made there.

Setting playeraction to 1 will make IsSitting() return true, which affects many other things, such as not being able to use skills/aa, being hit for max damage, and multiplying aggro.

When you changed playeraction did you test in combat to see if you could cast spells and such?
Reply With Quote
  #11  
Old 05-17-2011, 11:39 AM
Sikkun
Sarnak
 
Join Date: Apr 2011
Posts: 30
Default

When I tried the gethorseid() orginally like you are saying it did not work. I assumed this is because that code isn't updating all the time. (I havn't checked it again but I will).

Mine only sets playeraction = 1 when youare mounted + standing still. Which as far as my understanding on live ony a moun + being still = everything the same as sitting. So when you are on a mount and still logically IsSitting() should be true. Casting a spell/combat/aa will change the playeraction code. I have tested with some spell casting/combat and it was all working correctly (because all of those break /sit.

I'll test the spell casting/aa/combat some more and try to see if your work around works again.
Reply With Quote
  #12  
Old 05-17-2011, 11:53 AM
Sikkun
Sarnak
 
Join Date: Apr 2011
Posts: 30
Default

The other issue I can think of with your logic though is gethorseid() will be true all the time while your on a mount. Meaning if that fix did work you would get ooc regin the entire time you are on a horse. Meaning you would get ooc regin while moving.
Reply With Quote
  #13  
Old 05-18-2011, 11:12 AM
Sikkun
Sarnak
 
Join Date: Apr 2011
Posts: 30
Default

Alright so I'm going to try and clean this thread up some and share all of my testing results.

Mounted OOC Testing
5-18-2011

Test 0 Base Case
Unaltered EQEmulator Source
Results: With Database Rule enables OOC regeneration works while sitting but not while on a mount.

Test 1
Zone
Code:
client_process.cpp
void Client::CalcRestState() method
if(AggroCount || !IsSitting() || !GetHorseId())
		return;
Results:
Game does not add OOC regeneration while on a mount with this code
Most likely due to when/how this code updates. It also disables OOC regeneration while
/sit elemenating OOC regeneration from the game.

Test 2
Zone
client_process.cpp
Code:
void Client::CalcRestState() method
if(AggroCount || !IsSitting() || GetHorseId())
		return;
Results:
Game does not add OOC regeneration while on a mount with this code
Most likely due to when/how this code updates

So my testing shows that even though the logic of that code does seem right, it does not work (That was the first way I tried to fix the issue also).

Because of the issues brought up my code has changed a little and I will explain each part.

Test 3
(This first part allows the client to see the player as sitting when the player is mounted and still, when moving the client sees the player as standing. This allows for OOC regeneration while mounted, but stops regeneration when the player moves. All +argo, +dmg of sitting would still happen, this is because sitting on a mount is viewed the same /sit).

Zone
client_packet.cpp
void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) method
Insert code after // Break Hide if moving without sneaking and set rewind timer if moved
code block.

Code:
//allow player to have OOC regeneration on a mount
	if(ppu->y_pos == y_pos || ppu->x_pos == x_pos)
	{
		if(GetHorseId() != 0)
		{
			playeraction = 1;
		}
	}
	else if(ppu->y_pos != y_pos || ppu->x_pos != x_pos)
	{
		if(GetHorseId() != 0)
		{
			playeraction = 0;
		}
	}

(This second part tells the client that a user is "standing" when an aa ability is used this will stop OOC regen for that tick and allow a player to cast their aa ability while mounted. After the ability is used the OOC regeneration will start again on the next tick unless the AA used created an in combat situation.)

Zone
client_packet.cpp
void Client::Handle_OP_AAAction(const EQApplicationPacket *app) method
insert code before mlog(AA__IN, "Received OP_AAAction");

Code:
//check if you are on a mount
	if (GetHorseId() != 0)
	{
		playeraction = 0;
	}
(This final part simply sets the player to standing after they dismount. Without this the player would not be able to use an AA right after dismounting unless they moved, sat, etc.)

Zone
horse.cpp
void Client::SetHorseId(int16 horseid_in) method
Code:
void Client::SetHorseId(int16 horseid_in) {
	//if its the same, do nothing
	if(horseId == horseid_in)
		return;
	
	//otherwise it changed.
	//if we have a horse, get rid of it no matter what.
	if(horseId) {
		Mob *horse = entity_list.GetMob(horseId);
		if(horse != NULL)
		{
			horse->Depop();
			//set player to standing
			playeraction = 0;
		}
	}
	
	//now we take whatever they gave us.
	horseId = horseid_in;
}
Results: Player recieves OOC bonus while on a mount.
Extended Testing:
Test 1
Player moves
Results:
Player does not gain OOC bonus until they have come to a complete stop.

Test 2
Player is in combat
Results:
Player does not gain OOC bonus until compat has ended, OOC Timer is finished, and player is not moving.

Test 3
Player cast spell
Results
Spell cast as normal

Test 4
Player uses aa
Results: AA skill works as normal

Test 5
Player uses skill (Kick)
Results: Skill works as normal

Test 6
Player dismounts
Results: OOC regeneration stops

Test 7
Player dismounts and cast a spell
Results: Spell cast as normal

Test 8
Player dismounts and uses a aa skill
Results: AA works as normal

After all of this testing I am pretty confident in this fix. It maintains the rule set in the database so if OOC regeneration is turned off it will have no effect on the game. If anyone has any questions or any more testing they would like me to do feel free to let me know.

Sikkun
Reply With Quote
  #14  
Old 05-18-2011, 01:54 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,743
Default

You might try the logic that Sorvani posted, since mine was broken.

Does out of combat regen work on live while mounted? If not, you'll probably want to wrap an optional rule around it so the default behaviour is live like and the server op can change it if they want to.

Also, if you want to get this committed you should post a diff once you have it all working, since that's easy for someone to apply versus trying to copy/paste code out of a post manually and get it right.
Reply With Quote
  #15  
Old 05-18-2011, 02:43 PM
Sikkun
Sarnak
 
Join Date: Apr 2011
Posts: 30
Default

Test 1 was your logic and Test 2 was Sorvani's logic.
OOC regeneration does work on a mount on live so no rule needed if we are trying to emulate live.
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 06:42 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3