Go Back   EQEmulator Home > EQEmulator Forums > Support > Support::Windows Servers

Support::Windows Servers Support forum for Windows EQEMu users.

Reply
 
Thread Tools Display Modes
  #61  
Old 10-03-2015, 10:26 AM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

A little more progress on the pet thing.

The entire delete/save process (creating a new blank entry in table `character_pet_info`) for the DB in one spot. This eliminates running a couple unneeded queries from using the <SavePetInfo> function.

The pet window still appears on client. I don't know if this is avoidable by doing the norent check somewhere earlier in the process. It's not a big deal unless there is a cleaner/more efficient way to do this.

\client_process.cpp
Code:
	bool deletenorent = database.NoRentExpired(GetName());
	if (deletenorent) { //client was offline for more than 30 minutes, delete no rent items
		if (RuleB(Inventory, TransformSummonedBags))
			DisenchantSummonedBags(false);
		RemoveNoRent(false);

// added 9/30/15 no rent check (updated 10/3/15)
		if (!RuleB(Pets, PetLogPersistence))
		{
			SetPet(0);

			database.DeletePetInfo(this);
		}
	}
\zonedb.cpp
Code:
void ZoneDatabase::DeletePetInfo(Client *client)
{
	std::string query = StringFormat("DELETE FROM `character_pet_info` WHERE `char_id` = %u AND `pet` = 0", client->CharacterID());
	auto results = database.QueryDatabase(query);
	if (!results.Success())
		return;

	query = StringFormat("DELETE FROM `character_pet_buffs` WHERE `char_id` = %u AND `pet` = 0", client->CharacterID());
	results = database.QueryDatabase(query);
	if (!results.Success())
		return;

	query = StringFormat("DELETE FROM `character_pet_inventory` WHERE `char_id` = %u AND `pet` = 0", client->CharacterID());
	results = database.QueryDatabase(query);
	if (!results.Success())
		return;

	PetInfo *petinfo = client->GetPetInfo(0);

	memset(petinfo, 0, sizeof(struct PetInfo));

	int pet = 0;

	query = StringFormat("INSERT INTO `character_pet_info` "
		"(`char_id`, `pet`, `petname`, `petpower`, `spell_id`, `hp`, `mana`, `size`) "
		"VALUES (%u, %u, '%s', %i, %u, %u, %u, %f) "
		"ON DUPLICATE KEY UPDATE `petname` = '%s', `petpower` = %i, `spell_id` = %u, "
		"`hp` = %u, `mana` = %u, `size` = %f",
		client->CharacterID(), pet, petinfo->Name, petinfo->petpower, petinfo->SpellID,
		petinfo->HP, petinfo->Mana, petinfo->size, // and now the ON DUPLICATE ENTRIES
		petinfo->Name, petinfo->petpower, petinfo->SpellID, petinfo->HP, petinfo->Mana, petinfo->size);
	results = database.QueryDatabase(query);
	if (!results.Success())
		return;
	query.clear();
}
As an aside: While going through this process I noticed some queries are ran anywhere between 2-6 times from this maybe? <database.QueryDatabase(query);>

I understand my tinkering may have caused some of this but, I'm curious to know the purpose of this.

Thanks

EDIT:

Not sure if I mentioned this before. I had to add the line below when I created the item in \zonedb.cpp. Can't take it for granted.

\zonedb.h
Code:
	void DeletePetInfo(Client *c);
Reply With Quote
  #62  
Old 10-09-2015, 03:30 PM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

Good day.

I created a rule to force training of certain melee skills. The intention is to only force training if the skill is acquired after level 1.

For Riposte below,

\zone\attack.cpp(412)
Code:
		if (IsClient()) {
			if (!RuleB(Skills, TrainMeleeSkills)) {
				CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10);
			}
			else if (RuleB(Skills, TrainMeleeSkills) && CastToClient()->HasSkill(SkillRiposte)) {
				(CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10));
			}
		}
I'm concerned about what will happen when the rule is true and the character does not have <SkillRiposte>. Do I need some kind of escape from this if it goes beyond <else if>? There is quite a bit more code after what is quoted above.

This question applies to several similar issues I had concern about.

Thanks
Reply With Quote
  #63  
Old 10-09-2015, 04:48 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

If there's nothing left to process in the function after your 'else if' and the exclusion can be caught with an 'else' or another 'else if' statement, you can simply handle it with a 'return' statement.

Otherwise, you might consider putting your post-con check code inside of a single con check that meets all of the requirements for that code to be processed.
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #64  
Old 10-09-2015, 08:36 PM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

Thank you sir.

Quote:
If there's nothing left to process in the function after your 'else if' and the exclusion can be caught with an 'else' or another 'else if' statement, you can simply handle it with a 'return' statement.
I understand this.

Quote:
Otherwise, you might consider putting your post-con check code inside of a single con check that meets all of the requirements for that code to be processed.
I'm a little fuzzy on this.

I can't find it but I thought I saw an instance where <else> was used with nothing between { } except spaces.

EDIT: Here but this may not apply to my issue.
Code:
else {
				if (!GetFeigned() && (DistanceSquared(bindmob->GetPosition(), m_Position)  <= 400)) {
					// send bindmob bind done
					if(!bindmob->IsAIControlled() && bindmob != this ) {

					}
					else if(bindmob->IsAIControlled() && bindmob != this ) {
					// Tell IPC to resume??
					}
					else {
					// Binding self
					}
					// Send client bind done

					bind_out->type = 1; // Done
					QueuePacket(outapp);
					bind_out->type = 0;
					CheckIncreaseSkill(SkillBindWound, nullptr, 5);

					int maxHPBonus = spellbonuses.MaxBindWound + itembonuses.MaxBindWound + aabonuses.MaxBindWound;
Reply With Quote
  #65  
Old 10-09-2015, 09:45 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

Just wasted code space..though it may be there, with a remark, to indicate what is happening to arrive there or an area for future implementations.

The compiler will probably optimize out that particular else clause since there is nothing being processed.
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #66  
Old 10-09-2015, 09:48 PM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

Gotcha, thanks.
Reply With Quote
  #67  
Old 10-13-2015, 02:27 PM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

I've tried a different approach with no success, so I try here:

I'm trying to come up with a script which, I hope, will summon a corpse using the necro spell, id = 3 (summon corpse).

I've looked at the Dragons of Norrath and the guild lobby quests and they will no do what I want them to do. I want to summon a corpse with the same behavior as the NEC spell "summon corpse".

Everything appears to work except self targeting. Since the npc is targeted at the end of the script and the spell is self (player) cast, the text stating "Your target must be a group member for this spell." appears. I've also tried to change the actual spell effect code.

Below is what I have so far with <location of target code> to indicate where I think it should belong.

Code:
-- global\a_dungeon_necromancer.lua NPCID

function event_say(e)
	if(e.message:findi("hail")) then
		e.self:Say("I know the reason you come to see me, " .. e.other:GetName() .. ". Don't be afraid, the living do not concern me... You require my [services], you must ask for them. Only the willing are allowed when living.");
	elseif(e.message:findi("services")) then
		e.self:Say("" .. e.other:GetName() .. ", to perform the necessary incantation, you must hand me one platinum, three gold, three silver and seven copper pieces.");
	end
end

function event_trade(e)
	local item_lib = require("items");
	local leet_cash = 0;
	if(item_lib.check_turn_in(e.trade, {platinum = 1, gold = 3, silver = 3, copper = 7})) then

		leet_cash = 1;
	end

	if(leet_cash >= 1) then

--			<location of target code>
			
			eq.SelfCast(3);
			if(leet_cash == 1) then
				e.self:Say("Believe me when I say this exact amount represents the services offered.");
				leet_cash = 0;
		end

	end
	item_lib.return_items(e.self, e.other, e.trade)
end

If anyone knows how to accomplish what I am trying to do, please share.

Thanks
Reply With Quote
  #68  
Old 10-15-2015, 12:32 AM
provocating's Avatar
provocating
Demi-God
 
Join Date: Nov 2007
Posts: 2,175
Default

I do not even know why I am trying to help you at this point, but whatever.

You never explained WHY the guild summoner scripts could not be modified to do what you want. I mean they summon all of the players corpses. How does that not work?
Reply With Quote
  #69  
Old 10-15-2015, 01:02 AM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

Quote:
I do not even know why I am trying to help you at this point, but whatever.

You never explained WHY the guild summoner scripts could not be modified to do what you want. I mean they summon all of the players corpses. How does that not work?
I'm sorry if I hurt you, provocating. I can tell you for certain, I do not feel the same way. Grudges aren't healthy.

If I knew how to alter <EVENT_SUMMON();> to only work in specific zones or with specific corpses, I would not be asking the question.

Maybe it's clarification I need. I don't have much knowledge of scripts and this is why I asked the question to begin with, hoping, someone could clarify this.
Reply With Quote
  #70  
Old 10-15-2015, 01:32 AM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

$client->SetTarget($client);

That's all that was needed in the .pl file.

Code:
# global\a_dungeon_necromancer.pl NPCID


sub EVENT_SAY  {
	if ($text=~/hail/i) {
		quest::say("I know the reason you come to see me, $name. Don't be afraid, the living do not concern me... You require my [services], you must ask for them. Only the willing are allowed when living.");
	}
	if ($text=~/services/i) {
	    quest::say("$name, to perform the necessary incantation, you must hand me one platinum, three gold, three silver and seven copper pieces.");

	}
}

sub EVENT_ITEM {
	if (plugin::takeCoin(1000)) {
		quest::say("Believe me when I say this exact amount represents the services offered and becomes transmuted into the much larger pile of where, I only know. HAHA!");
		$client->SetTarget($client);
		quest::selfcast(3);
	}
	plugin::returnUnusedItems();
}
Thanks

PS. Could use a writer.
Reply With Quote
  #71  
Old 10-15-2015, 04:51 AM
Noport
Opcode Ninja
 
Join Date: Mar 2009
Location: San francisco
Posts: 426
Default

Feel free to try this have no idea where npc location or for what zone i had no way to test this perl script.

a_dungeon_necromancer.pl
Code:
EVENT_SAY  {
if ($text=~/hail/i) {
quest::say("I know the reason you come to see me, $name. Don't be afraid, the living do not concern me... You require my [services], you must ask for them. Only the willing are allowed when living.");
}
if ($text=~/services/i) {
quest::say("$name, to perform the necessary incantation, you must hand me one platinum, three gold, three silver and seven copper pieces.");
}
}
sub EVENT_ITEM{
if (($platinum>=1) (($Gold>=3) ((Silver>=3) (($Copper>=7{)) then
$npc->SetAppearance(0);
$client->Message("Believe me when I say this exact amount represents the services offered.");
quest::summonburriedplayercorpse($charid, $x, $y, $z, 0);
$corpse = 0;
$charid = 0;
else{
quest::say("Thank you for your donation $name, it wasn't enough though ...");
 }
} 
sub EVENT_ITEM {
quest::say("I have no use for this, $name.");
plugin::return_items(\%itemcount);
}
Reply With Quote
  #72  
Old 10-15-2015, 02:49 PM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

Thank you Noport.
Reply With Quote
  #73  
Old 10-16-2015, 04:15 PM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

I added a mechanic to <channelchance> and am wondering if it looks right or if it could be done better. It may be a little confusing but the purpose was learning as much as adding this code. It's an exercise in futility trying to channel at lower levels and the added mechanic mitigates this a bit. It also reinforces those who practice skills when they level, like the old days.

Also, the <distance_moved> and <distancemod> formulas do not do as advertised. The idea seems proper but the implementation is off. I will add to this my results when I get to it.

The big thing I am wondering is if the code in the header is returning the value for the previous level max skill. This mechanic seems to work upon initial testing.

\zone\client.h(695)
Code:
	inline uint16 PrevMaxSkill(SkillUseTypes skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()-1); }
\zone\spells.cpp(1105) - <void Mob::CastedSpellFinished>
Code:
				// max 93% chance at 252 skill
				channelchance = 30 + GetSkill(SkillChanneling) / 400.0f * 100;
				
				uint16 cS = CastToClient()->GetRawSkill(SkillChanneling); // current skill
				uint16 mS = CastToClient()->MaxSkill(SkillChanneling); // current level max skill
				uint16 pS = CastToClient()->PrevMaxSkill(SkillChanneling); // current level - 1 max skill
				double iA = 20 / (mS - pS); // adjustment interval
				double cA = 0; // cA = adjustement coefficient
				double param, result;
				param = (pow((.0005*cS), 2));

				while (true)
				{
					if (cS >= 200) { 
						break;
					}					
					else if (cS <= pS) {
						break;
					}
					else if (GetLevel () <= 1) {
						cA = (cS * 2);
						result = cA - param;
						channelchance += result;
						break;
					}
					else {
						cA = ((cS - pS)*iA);
						result = cA - param;
						channelchance += result;						
					}
					break;
				}
				channelchance -= attacked_count * 2;
				channelchance += channelchance * channelbonuses / 100.0f;
			}

<snip code>
					distance_moved = d_x * d_x + d_y * d_y;
					// if you moved 1 unit, that's 25% off your chance to regain.
					// if you moved 2, you lose 100% off your chance
					distancemod = distance_moved * 25;
					channelchance -= distancemod;
				}
Thanks

EDIT: here is a visualization of the behavior http://prnt.sc/8s311y

The blue line is the current, unadjusted channelchance. The lower red function is the formula I added. The upper red function is max skill channelchance after adding the the formula.
Reply With Quote
  #74  
Old 10-16-2015, 09:01 PM
AdrianD
Discordant
 
Join Date: Dec 2013
Posts: 297
Default

Quote:
Also, the <distance_moved> and <distancemod> formulas do not do as advertised. The idea seems proper but the implementation is off. I will add to this my results when I get to it.
I think I misinterpreted this. Disregard.
Reply With Quote
Reply

Thread Tools
Display Modes

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 10:21 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