Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Bots

Development::Bots Forum for bots.

Reply
 
Thread Tools Display Modes
  #1  
Old 07-08-2011, 06:17 PM
Criimson
Hill Giant
 
Join Date: Sep 2006
Posts: 172
Default My Bot included binaries

Hello everyone

I play on a solo server and love bots, so have been kind of tweaking them with tons of help from the emu community. As I was playing today in Upper Guk and having a blast it dawned on me that others might enjoy the changes that are kind of an offshoot of the standard binaries. So if anyone is interested in having me email them my compiled binaries feel free to shoot me a PM with your email and I'll send them to you. I understand that not everyone compiles their own binaries and with all the help I've gotten I love to help a little too.

What is different:
SQL - One minor sql change. Added the enchanter bot spells that allow it to automatically mez adds (only have up to level 60 atm will add more soon - I level super slowly)

Bot changes -
Added pfyons archetype code as well as his code to have cleric not DD till oom - slightly modified to have the cleric only use DDs if over 75% mana
Modified that code to have chanters stop using DDs at 50% mana
Modified healing AI so that hybrids (ie Beasts, Rangers and Pallys) only cast heals when someone is below 20% health
Enchanters will automez adds (removed the !addMob spam when no adds are present)
Altered pacify code so only one group member casts pacify and priority is given to the enchanter
Added #bot setfollowdistance command in case it bothers you that bots are stacked (still have to redo command after you zone for now)

Umm think thats all for now

Anyway, if anyone is interested I'll get it to you asap.

Criimson

EDIT: oh yea I compile using the svn so for everything to run smoothly you have to have your PEQ db updated to the lastest release
EDIT EDIT: Sorry tired And the bianries are for windows servers - if someone wants em for linux (I assume you can compile) I can send the sources
Reply With Quote
  #2  
Old 07-09-2011, 04:34 AM
Criimson
Hill Giant
 
Join Date: Sep 2006
Posts: 172
Default

Here are the diff files for those of you that requested them.

<bot.h>
Code:
295d294
< 	static bool GroupHasEnchanterClass(Group* group) { return GroupHasClass(group, ENCHANTER); }
<bot.cpp>
Code:
10079d10078
< 		c->Message(0, "#bot setfollowdistance ### - sets target bots follow distance to ### (ie 30 or 250).");
10457,10481d10455
< 	//Criimson: Bot follow distance - SetFollowDistance
< 	if(!strcasecmp(sep->arg[1], "setfollowdistance")) {
< 		if((c->GetTarget() == NULL) || (c->GetTarget() == c) || (!c->GetTarget()->IsBot()) ) {
< 			c->Message(15, "You must target a bot!");
< 		}
< 		else {
< 			int32 BotFollowDistance = atoi(sep->arg[2]);
< 			c->GetTarget()->SetFollowDistance(BotFollowDistance);
< 		}
< 
< 		return;
< 	}
< 
< 
< 	if(!strcasecmp(sep->arg[1], "picklock")) {
< 		if((c->GetTarget() == NULL) || (c->GetTarget() == c) || !c->GetTarget()->IsBot() || (c->GetTarget()->GetClass() != ROGUE)) {
< 			c->Message(15, "You must target a rogue bot!");
< 		}
< 		else {
< 			entity_list.BotPickLock(c->GetTarget()->CastToBot());
< 		}
< 
< 		return;
< 	}
< 
10939,10946d10912
< 							//Criimson: Reordered code - was giving priority to bard
< 						case DRUID:
< 							// Unless we have a ranger, druid is next best.
< 							if(TrackerClass != RANGER) {
< 								Tracker = g->members[i];
< 								TrackerClass = DRUID;
< 							}
< 							break;
10954c10920,10926
< 			
---
> 						case DRUID:
> 							// Unless we have a ranger, druid is next best.
> 							if(TrackerClass != RANGER) {
> 								Tracker = g->members[i];
> 								TrackerClass = DRUID;
> 							}
> 							break;
11379,11396c11351
< 					//Criimson - seperated cleric and chanter so chanter is primary
< 					if(g && g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == ENCHANTER)) {
< 						Bot *pacer = g->members[i]->CastToBot();
< 						pacer->Say("Trying to pacify %s \n", target->GetCleanName());
< 
< 						if(pacer->Bot_Command_CalmTarget(target)) {
< 							if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm))
< 							//if(pacer->IsPacified(target))
< 								c->Message(0, "I have successfully pacified %s.", target->GetCleanName());
< 								return;
< 							/*else
< 								c->Message(0, "I failed to pacify %s.", target->GetCleanName());*/
< 						}
< 						else
< 							c->Message(0, "I failed to pacify %s.", target->GetCleanName());
< 					}
< 					//Criimson - seperated cleric and chanter so chanter is primary
< 					if(g && g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == CLERIC) && (GroupHasEnchanterClass(g) == false)) {
---
> 					if(g && g->members[i] && g->members[i]->IsBot() && ((g->members[i]->GetClass() == ENCHANTER) || g->members[i]->GetClass() == CLERIC)) {
11404d11358
< 								return;
13304,13305c13258
< 	//CRIIMSON: Changed so heal based on health percentage is different for hybrids
< 	if( botCasterClass == CLERIC || botCasterClass == DRUID || botCasterClass == SHAMAN) {
---
> 	if( botCasterClass == CLERIC || botCasterClass == DRUID || botCasterClass == SHAMAN || botCasterClass == PALADIN || botCasterClass == BEASTLORD || botCasterClass == RANGER) {
13350,13395d13302
< 		//CRIIMSON: Changed so heal based on health percentage is different for hybrids
< 		if( botCasterClass == PALADIN || botCasterClass == BEASTLORD || botCasterClass == RANGER) {
< 		//If AI_EngagedCastCheck() said to the healer that he had to heal
< 		if( iSpellTypes == SpellType_Heal )	{
< 			// check in group
< 			if(caster->HasGroup()) {
< 				Group *g = caster->GetGroup();
< 				
< 				if(g) {
< 					for(int i = 0; i < MAX_GROUP_MEMBERS; i++) {
< 						if(g->members[i] && !g->members[i]->qglobal) {
< 							if(g->members[i]->IsClient() && g->members[i]->GetHPRatio() < 20) {
< 								if(caster->AICastSpell(g->members[i], iChance, SpellType_Heal))
< 									return true;
< 							}
< 							else if((g->members[i]->GetClass() ==  WARRIOR || g->members[i]->GetClass() == PALADIN || g->members[i]->GetClass() == SHADOWKNIGHT) &&
< 								g->members[i]->GetHPRatio() < 20) 
< 							{
< 								if(caster->AICastSpell(g->members[i], 100, SpellType_Heal))
< 									return true;
< 							}
< 							else if(g->members[i]->GetClass() ==  ENCHANTER && g->members[i]->GetHPRatio() < 20) {
< 								if(caster->AICastSpell(g->members[i], 100, SpellType_Heal))
< 									return true;
< 							}
< 							else if(g->members[i]->GetHPRatio() < 20) {
< 								if(caster->AICastSpell(g->members[i], 100, SpellType_Heal))
< 									return true;
< 							}
< 						}
< 
< 						if(g->members[i] && !g->members[i]->qglobal && g->members[i]->HasPet() && g->members[i]->GetPet()->GetHPRatio() < 20) {
< 							if(g->members[i]->GetPet()->GetOwner() != caster && caster->IsEngaged() && g->members[i]->IsCasting() && g->members[i]->GetClass() != ENCHANTER )
< 								continue;
< 
< 							if(caster->AICastSpell(g->members[i]->GetPet(), 100, SpellType_Heal))
< 								return true;
< 						}
< 					}
< 				}
< 			}
< 
< 			// TODO: raid heals
< 		}
< 	}
< 	
13427d13333
<
<botspellsai.cpp> (mainly pfyons archetype code)
Code:
256,278d255
< 					switch(tar->GetArchetype())
< 					{
< 						case ARCHETYPE_CASTER:
< 							//TODO: probably more caster specific spell effects in here
< 							if(IsEffectInSpell(selectedBotSpell.SpellId, SE_AttackSpeed) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ATK) ||
< 								 IsEffectInSpell(selectedBotSpell.SpellId, SE_STR) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ReverseDS))
< 							{
< 								continue;
< 							}
< 							break;
< 						case ARCHETYPE_MELEE:
< 							//TODO: Include mana regen (breeze/clarity/etc), I don't know what spell effect it is
< 							if(IsEffectInSpell(selectedBotSpell.SpellId, SE_IncreaseSpellHaste))
< 							{
< 								continue;
< 							}
< 							break;
< 						case ARCHETYPE_HYBRID:
< 							//Hybrids get all buffs
< 						default:
< 							break;
< 					}
< 
323,333d299
< 				if(botClass == CLERIC && this->GetManaRatio() <= 75.0f)
< 				{
< 					//If we're at 75% mana or below, don't nuke as a cleric or 50% as enchanter
< 					break;
< 				}
< 				if(botClass == ENCHANTER && this->GetManaRatio() <= 50.0f)
< 				{
< 					//If we're at 75% mana or below, don't nuke as a cleric or 50% as enchanter
< 					break;
< 				}
< 
569,571c535,536
< 					if(!addMob){
< 						//Say("!addMob.");
< 						break;}
---
> 					if(!addMob)
> 						break;
577d541
< 
580c544
< 			}
---
> 							}
761,762d724
< 
< 
1352c1314
< 		
---
>
These are needed from pfyons cleric/archetype code:

<mob.h>
Code:
55,66d54
< #define APPEAR_HEIGHT	0x001d
< #define	APPEAR_HP_TIC	0x0011
<  
< #define ARCHETYPE_HYBRID	1
< #define ARCHETYPE_CASTER	2
< #define ARCHETYPE_MELEE		3
< 
< #define CON_GREEN		2
< #define CON_LIGHTBLUE	18
< #define CON_BLUE		4
< 
< 
684,687c672,674
<  	char GetCasterClass() const;
< 	uint8 GetArchetype() const;
<  	virtual sint32 CalcMaxMana();
<  
---
> 	char GetCasterClass() const;
> 	virtual sint32 CalcMaxMana();
>
<mob.cpp>
Code:
675,721d674
< uint8 Mob::GetArchetype() const {
< 	switch(class_)
< 	{
< 	case PALADIN:
< 	case RANGER:
< 	case SHADOWKNIGHT:
< 	case BARD:
< 	case BEASTLORD:
< 	case PALADINGM:
< 	case RANGERGM:
< 	case SHADOWKNIGHTGM:
< 	case BARDGM:
< 	case BEASTLORDGM:
< 		return ARCHETYPE_HYBRID;
< 		break;
< 	case CLERIC:
< 	case DRUID:
< 	case SHAMAN:
< 	case NECROMANCER:
< 	case WIZARD:
< 	case MAGICIAN:
< 	case ENCHANTER:
< 	case CLERICGM:
< 	case DRUIDGM:
< 	case SHAMANGM:
< 	case NECROMANCERGM:
< 	case WIZARDGM:
< 	case MAGICIANGM:
< 	case ENCHANTERGM:
< 		return ARCHETYPE_CASTER;
< 		break;
< 	case WARRIOR:
< 	case MONK:
< 	case ROGUE:
< 	case BERSERKER:
< 	case WARRIORGM:
< 	case MONKGM:
< 	case ROGUEGM:
< 	case BERSERKERGM:
< 		return ARCHETYPE_MELEE;
< 		break;
< 	default:
< 		return ARCHETYPE_HYBRID;
< 		break;
< 	}
< }
<
This is the sql to add chanter mez spells to its AI in the DB

Code:
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`) VALUES (8145, 705, 190, 2048, 47, 55);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`) VALUES (8146, 705, 292, 2048, 2, 55);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`) VALUES (8147, 705, 187, 2048, 13, 55);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`) VALUES (8148, 705, 188, 2048, 30, 55);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`) VALUES (8150, 705, 1691, 2048, 54);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`) VALUES (8151, 705, 1692, 2048, 59);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`) VALUES (8152, 705, 3341, 2048, 60);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`) VALUES (8153, 705, 3341, 2048, 61);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`) VALUES (8154, 705, 3354, 2048, 63);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`) VALUES (8155, 705, 3358, 2048, 64);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`) VALUES (8156, 705, 5503, 2048, 67);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`) VALUES (8157, 705, 8035, 2048, 68);
INSERT INTO `npc_spells_entries` (`id`, `npc_spells_id`, `spellid`, `type`, `minlevel`) VALUES (8158, 705, 5520, 2048, 69);
This only includes the spells up to level 70.

Criimson

EDIT: AoE mezzes arent going to be inluded until I add some code to check for number to be mezzed at some point. Say 3+ and chanter will aoe mez, but for now the bot is pretty damn fast once it starts mezzing. The only tweak is that it tends to tash the MT before it starts mezzing...will work on that soon.
Reply With Quote
  #3  
Old 07-09-2011, 05:48 AM
Criimson
Hill Giant
 
Join Date: Sep 2006
Posts: 172
Default

Had to update Bot.cpp
I always run a chanter and cleric and didnt notice that clerics weren't pacifying. Added a more proper check for chanter in the group.

Use this diff instead of the one above.

Code:
10079d10078
< 		c->Message(0, "#bot setfollowdistance ### - sets target bots follow distance to ### (ie 30 or 250).");
10457,10481d10455
< 	//Criimson added Bot follow distance - SetFollowDistance
< 	if(!strcasecmp(sep->arg[1], "setfollowdistance")) {
< 		if((c->GetTarget() == NULL) || (c->GetTarget() == c) || (!c->GetTarget()->IsBot()) ) {
< 			c->Message(15, "You must target a bot!");
< 		}
< 		else {
< 			int32 BotFollowDistance = atoi(sep->arg[2]);
< 			c->GetTarget()->SetFollowDistance(BotFollowDistance);
< 		}
< 
< 		return;
< 	}
< 
< 
< 	if(!strcasecmp(sep->arg[1], "picklock")) {
< 		if((c->GetTarget() == NULL) || (c->GetTarget() == c) || !c->GetTarget()->IsBot() || (c->GetTarget()->GetClass() != ROGUE)) {
< 			c->Message(15, "You must target a rogue bot!");
< 		}
< 		else {
< 			entity_list.BotPickLock(c->GetTarget()->CastToBot());
< 		}
< 
< 		return;
< 	}
< 
10939,10946d10912
< 							//Criimson: Reordered code - was giving priority to bard
< 						case DRUID:
< 							// Unless we have a ranger, druid is next best.
< 							if(TrackerClass != RANGER) {
< 								Tracker = g->members[i];
< 								TrackerClass = DRUID;
< 							}
< 							break;
10954c10920,10926
< 			
---
> 						case DRUID:
> 							// Unless we have a ranger, druid is next best.
> 							if(TrackerClass != RANGER) {
> 								Tracker = g->members[i];
> 								TrackerClass = DRUID;
> 							}
> 							break;
11377d11348
< 				bool DoesGroupHaveEnchanter = false;
11380,11403c11351
< 					if(g && g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == ENCHANTER)) {
< 						DoesGroupHaveEnchanter = true;
< 					}
< 				}
< 
< 				for(int i=0; i<MAX_GROUP_MEMBERS; i++) {
< 					//Criimson - seperated cleric and chanter so chanter is primary
< 					if(g && g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == ENCHANTER)) {
< 						Bot *pacer = g->members[i]->CastToBot();
< 						pacer->Say("Trying to pacify %s \n", target->GetCleanName());
< 
< 						if(pacer->Bot_Command_CalmTarget(target)) {
< 							if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm))
< 							//if(pacer->IsPacified(target))
< 								c->Message(0, "I have successfully pacified %s.", target->GetCleanName());
< 								return;
< 							/*else
< 								c->Message(0, "I failed to pacify %s.", target->GetCleanName());*/
< 						}
< 						else
< 							c->Message(0, "I failed to pacify %s.", target->GetCleanName());
< 					}
< 					//Criimson - seperated cleric and chanter so chanter is primary
< 					if(g && g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == CLERIC) && (DoesGroupHaveEnchanter == false)) {
---
> 					if(g && g->members[i] && g->members[i]->IsBot() && ((g->members[i]->GetClass() == ENCHANTER) || g->members[i]->GetClass() == CLERIC)) {
11411d11358
< 								return;
13311,13312c13258
< 	//CRIIMSON: Changed so heal based on health percentage is different for hybrids
< 	if( botCasterClass == CLERIC || botCasterClass == DRUID || botCasterClass == SHAMAN) {
---
> 	if( botCasterClass == CLERIC || botCasterClass == DRUID || botCasterClass == SHAMAN || botCasterClass == PALADIN || botCasterClass == BEASTLORD || botCasterClass == RANGER) {
13357,13402d13302
< 		//CRIIMSON: Changed so heal based on health percentage is different for hybrids
< 		if( botCasterClass == PALADIN || botCasterClass == BEASTLORD || botCasterClass == RANGER) {
< 		//If AI_EngagedCastCheck() said to the healer that he had to heal
< 		if( iSpellTypes == SpellType_Heal )	{
< 			// check in group
< 			if(caster->HasGroup()) {
< 				Group *g = caster->GetGroup();
< 				
< 				if(g) {
< 					for(int i = 0; i < MAX_GROUP_MEMBERS; i++) {
< 						if(g->members[i] && !g->members[i]->qglobal) {
< 							if(g->members[i]->IsClient() && g->members[i]->GetHPRatio() < 20) {
< 								if(caster->AICastSpell(g->members[i], iChance, SpellType_Heal))
< 									return true;
< 							}
< 							else if((g->members[i]->GetClass() ==  WARRIOR || g->members[i]->GetClass() == PALADIN || g->members[i]->GetClass() == SHADOWKNIGHT) &&
< 								g->members[i]->GetHPRatio() < 20) 
< 							{
< 								if(caster->AICastSpell(g->members[i], 100, SpellType_Heal))
< 									return true;
< 							}
< 							else if(g->members[i]->GetClass() ==  ENCHANTER && g->members[i]->GetHPRatio() < 20) {
< 								if(caster->AICastSpell(g->members[i], 100, SpellType_Heal))
< 									return true;
< 							}
< 							else if(g->members[i]->GetHPRatio() < 20) {
< 								if(caster->AICastSpell(g->members[i], 100, SpellType_Heal))
< 									return true;
< 							}
< 						}
< 
< 						if(g->members[i] && !g->members[i]->qglobal && g->members[i]->HasPet() && g->members[i]->GetPet()->GetHPRatio() < 20) {
< 							if(g->members[i]->GetPet()->GetOwner() != caster && caster->IsEngaged() && g->members[i]->IsCasting() && g->members[i]->GetClass() != ENCHANTER )
< 								continue;
< 
< 							if(caster->AICastSpell(g->members[i]->GetPet(), 100, SpellType_Heal))
< 								return true;
< 						}
< 					}
< 				}
< 			}
< 
< 			// TODO: raid heals
< 		}
< 	}
< 	
13434d13333
<
Criimson

Next I will be working on:
Character's pets breaking mez - bot pets work properly, but personal pets just hit the first thing that hits you. That is like early live (in fact when EQ was released I played a necro and i remember if I died my pet would go ape shit on the group. Was funny looking back, but they had to change it quickly because people got mad when they got wiped by a dead necros pet), but was changed at some point so pets stopped breaking mez.
Personal pet trying to keep attacking a dead MoB that has a dot on player.
Reply With Quote
  #4  
Old 07-09-2011, 09:27 PM
louis1016
Hill Giant
 
Join Date: Dec 2009
Posts: 157
Default

This is really awesome of you to post these, but how do I add these to my code? I can do it manually but I just dont know what lines 10457,10481d10455 for example means.
Reply With Quote
  #5  
Old 07-10-2011, 01:30 AM
Karayrem
Sarnak
 
Join Date: Jan 2011
Posts: 33
Default

those looks nice. but I have no idea how to apply those diff to the original. Not a programming expert. I tried but it's a bit confusing for me to try to merge those in.
Reply With Quote
  #6  
Old 07-10-2011, 03:28 AM
Criimson
Hill Giant
 
Join Date: Sep 2006
Posts: 172
Default

We're all learning here. I couldn't even make a diff patch yesterday.

I found how to do it.

Basically download <Diff Patch Program>

Then to make my life easier I copied the trunk files:
bot.h
mob.h
bot.cpp
botspellsai.cpp
mob.cpp

into a directory on C: (I named mine "e" for simplicity).
Then I have each section of code (the patch files) saved to that directory. Each named to correspond to the file it is patching. For instance, the bot.h patch I named bot_h.

Once all are in the same directory, I hit the windows start button, typed CMD in the search area to run the command line program for windows.

Next type:
cd C:\Program Files (x86)\GnuWin32\bin

Then for each file to be patched type:
sdiff <patch file> <file to patch>

Example:

sdiff c:\e\bot_h c:\e\bot.h

And let it run. Then copy the patched files back to the directory \zone wherever you have your source code.

I use 2 source directories. One for the trunk that I update and one that I tinker in.

Hope this helps.

Criimson

EDIT:
As to what the numbers mean: they are the line numbers that are being altered. They are handy for patching the file by hand. For instance, when I patched in pfyons code the trunk was already ahead of when he posted the code. In VC what you do to patch in the file by hand is look at those numbers and hit CTRL-G. This will pop up a window and allow you to enter the line number you want to jump to. Then look for the code section that you are going to alter. It most likely won't be in the exact place, but it should be close.
Reply With Quote
  #7  
Old 07-10-2011, 08:11 AM
pfyon's Avatar
pfyon
Discordant
 
Join Date: Mar 2009
Location: Ottawa
Posts: 495
Default

I think tortoise svn has the ability to create and apply diffs.

If you're using linux, you can also use the 'diff' and 'patch' programs.
Reply With Quote
  #8  
Old 07-10-2011, 01:43 PM
sorvani
Dragon
 
Join Date: May 2010
Posts: 965
Default

yes tortoise does and works fine, but it is not obvious in the menu until you go looking for it.
Reply With Quote
  #9  
Old 07-10-2011, 01:55 PM
Criimson
Hill Giant
 
Join Date: Sep 2006
Posts: 172
Default

So I noticed when I hit level 13 (I have exp set to 0.1 on my server) that my chanter stopped mezzing. Looking into it.

Run this SQL

UPDATE `npc_spells_entries` SET `priority`=1 WHERE `priority`=0 AND `npc_spells_id`=705;

This seems to fix it, but it just brings up that chanter spells need better prioritizing in the code. That is where I am going to work while I await hearing from the PEQ team.

Criimson

Last edited by Congdar; 07-10-2011 at 06:02 PM..
Reply With Quote
  #10  
Old 07-10-2011, 02:17 PM
Karayrem
Sarnak
 
Join Date: Jan 2011
Posts: 33
Default

hmm well I do a copy and paste of the patch files to a blank text file. Not sure what to save it as. because when I did, the command:

sdiff c:\e\bot_h c:\e\bot.h

It tells me there's no such files or directory. so I tried saving as diff file. and tried again using this way.

sdiff c:\e\bot_h.diff c:\e\bot.h

I didn't get any error but it doesnt seems to apply the patch. I open it up and there was no changes.
Reply With Quote
  #11  
Old 07-10-2011, 02:24 PM
Congdar
Developer
 
Join Date: Jul 2007
Location: my own little world
Posts: 751
Default

updating the entire npc_spells_entries table like this is not a good idea since bots are not the only ones using this table and the priority field. Something closer to WHERE priority=0 AND npc_spells_id>700 AND npc_spells_id<713;
__________________
The Realm
Reply With Quote
  #12  
Old 07-10-2011, 03:14 PM
Criimson
Hill Giant
 
Join Date: Sep 2006
Posts: 172
Default

Yea I tried to edit it, but the timer on this forum disallowed it.

Here are some small updates. Tightening the DB side.

UPDATE `npc_spells_entries` SET `priority`=1 WHERE `priority`=0 AND 'npc_spells_id' = 705;
UPDATE `npc_spells_entries` SET `priority`=8 WHERE `priority`=7 AND 'npc_spells_id' = 705;
UPDATE `npc_spells_entries` SET `priority`=7 WHERE `priority`=6 AND 'npc_spells_id' = 705;
UPDATE `npc_spells_entries` SET `priority`=6 WHERE `priority`=5 AND 'npc_spells_id' = 705;
UPDATE `npc_spells_entries` SET `priority`=5 WHERE `priority`=4 AND 'npc_spells_id' = 705;
UPDATE `npc_spells_entries` SET `priority`=4 WHERE `priority`=3 AND 'npc_spells_id' = 705;
UPDATE `npc_spells_entries` SET `priority`=3 WHERE `priority`=2 AND 'npc_spells_id' = 705;
UPDATE `npc_spells_entries` SET `priority`=2 WHERE `priority`=1 AND TYPE != 2048 AND 'npc_spells_id' = 705;

UPDATE `npc_spells_entries` SET `maxlevel`=12 WHERE `id`=8146 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=29 WHERE `id`=8147 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=51 WHERE `id`=8148 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=53 WHERE `id`=8149 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=58 WHERE `id`=8150 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=59 WHERE `id`=8151 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=60 WHERE `id`=8152 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=62 WHERE `id`=8153 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=63 WHERE `id`=8154 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=66 WHERE `id`=8155 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=67 WHERE `id`=8156 LIMIT 1;
UPDATE `npc_spells_entries` SET `maxlevel`=68 WHERE `id`=8157 LIMIT 1;


Unsure why but it seems debuffs are still given priority which is weird. Created a level 65 team (sk/cleric/and chanter) and the chanter only starts mezzing once it throws all of its debuffs. Rune line also can get priority sometimes it seems (at least at lower levels). When I type #bot debug spells it shows the spell priority listing and they all seem fine, but the weird part is: the only place I see a call to the spell priority column from the code is in that one debug statement. Probably missing it somewhere though.

If anyone has any ideas let me know

EDIT:
In the code:
Code:
else if(botClass == ENCHANTER) {
			if (!AICastSpell(GetTarget(), 100, SpellType_Mez)) {
				if (!AICastSpell(GetTarget(), 100, SpellType_Slow)) {
					if (!AICastSpell(GetTarget(), 50, SpellType_Debuff)) {
						if (!AICastSpell(this, 100, SpellType_Pet)) {
							if (!AICastSpell(GetTarget(), 25, SpellType_DOT)) {
								if (!AICastSpell(GetTarget(), 25, SpellType_Nuke)) {
									if(!AICastSpell(GetTarget(), 50, SpellType_Escape)) {
										//
									}
								}
							}
						}
					}
				}
			}

			result = true;
		}
Is there a reason that spells arent cast in the order listed in the code?
Reply With Quote
  #13  
Old 07-10-2011, 03:22 PM
Criimson
Hill Giant
 
Join Date: Sep 2006
Posts: 172
Default

Quote:
Originally Posted by Karayrem View Post
hmm well I do a copy and paste of the patch files to a blank text file. Not sure what to save it as. because when I did, the command:

sdiff c:\e\bot_h c:\e\bot.h

It tells me there's no such files or directory. so I tried saving as diff file. and tried again using this way.

sdiff c:\e\bot_h.diff c:\e\bot.h

I didn't get any error but it doesnt seems to apply the patch. I open it up and there was no changes.
When I saved it using notepad I made sure to save it without any file extension.
Reply With Quote
  #14  
Old 07-10-2011, 03:46 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

You might try making a unified diff which is very easy to apply using tortoise or patch. Another benefit is that it will include some context lines for people trying to apply the changes manually.
Reply With Quote
  #15  
Old 07-10-2011, 03:55 PM
Criimson
Hill Giant
 
Join Date: Sep 2006
Posts: 172
Default

Quote:
Originally Posted by lerxst2112 View Post
You might try making a unified diff which is very easy to apply using tortoise or patch. Another benefit is that it will include some context lines for people trying to apply the changes manually.
Thank you
I'll try that. Never made one before and just googled how.

Criimson

EDIT:
Here is the tortoise diff

Code:
Index: bot.cpp
===================================================================
--- bot.cpp	(revision 1958)
+++ bot.cpp	(working copy)
@@ -1212,7 +1212,8 @@
 			mitigation += GetLevel() * 13/10;	//the 13/10 might be wrong, but it is close...
 	}
 	int displayed = 0;
-	displayed += ((avoidance+mitigation)*1000)/847;	//natural AC
+	//displayed += ((avoidance+mitigation)*1000)/847;
+	displayed += ((avoidance+mitigation)*500)/950;	//natural AC
 
 	//Iksar AC, untested
 	if(GetRace() == IKSAR)
@@ -10076,6 +10077,7 @@
 		c->Message(0, "#bot botgroup help - Displays the commands available to manage BOT ONLY groups.");
 		c->Message(0, "#bot mana [<bot name or target> | all] - Displays a mana report for all your spawned bots.");
 		c->Message(0, "#bot [hair|haircolor|beard|beardcolor|face|eyes|heritage|tattoo|details <value>] - Change your BOTs appearance.");
+		c->Message(0, "#bot setfollowdistance ### - sets target bots follow distance to ### (ie 30 or 250).");
 		// TODO:
 		// c->Message(0, "#bot illusion <bot/client name or target> - Enchanter Bot cast an illusion buff spell on you or your target.");
 		c->Message(0, "#bot pull [<bot name>] [target] - Bot Pulling Target NPC's");
@@ -10453,6 +10455,31 @@
 		return;
 	}
 
+	//Criimson added Bot follow distance - SetFollowDistance
+	if(!strcasecmp(sep->arg[1], "setfollowdistance")) {
+		if((c->GetTarget() == NULL) || (c->GetTarget() == c) || (!c->GetTarget()->IsBot()) ) {
+			c->Message(15, "You must target a bot!");
+		}
+		else {
+			int32 BotFollowDistance = atoi(sep->arg[2]);
+			c->GetTarget()->SetFollowDistance(BotFollowDistance);
+		}
+
+		return;
+	}
+
+
+	if(!strcasecmp(sep->arg[1], "picklock")) {
+		if((c->GetTarget() == NULL) || (c->GetTarget() == c) || !c->GetTarget()->IsBot() || (c->GetTarget()->GetClass() != ROGUE)) {
+			c->Message(15, "You must target a rogue bot!");
+		}
+		else {
+			entity_list.BotPickLock(c->GetTarget()->CastToBot());
+		}
+
+		return;
+	}
+
 	if(!strcasecmp(sep->arg[1], "archery")) {
 		if((c->GetTarget() == NULL) || (c->GetTarget() == c) || !c->GetTarget()->IsBot()) {
 			c->Message(15, "You must target a bot!");
@@ -10910,6 +10937,14 @@
 							Tracker = g->members[i];
 							TrackerClass = RANGER;
 							break;
+							//Criimson: Reordered code - was giving priority to bard
+						case DRUID:
+							// Unless we have a ranger, druid is next best.
+							if(TrackerClass != RANGER) {
+								Tracker = g->members[i];
+								TrackerClass = DRUID;
+							}
+							break;
 						case BARD:
 							// If we haven't found a tracker yet, use bard.
 							if(TrackerClass == 0) {
@@ -10917,13 +10952,7 @@
 								TrackerClass = BARD;
 							}
 							break;
-						case DRUID:
-							// Unless we have a ranger, druid is next best.
-							if(TrackerClass != RANGER) {
-								Tracker = g->members[i];
-								TrackerClass = DRUID;
-							}
-							break;
+			
 						default:
 							break;
 					}
@@ -11346,9 +11375,17 @@
 		else {
 			if(c->IsGrouped()) {
 				Group *g = c->GetGroup();
+				bool DoesGroupHaveEnchanter = false;
 
 				for(int i=0; i<MAX_GROUP_MEMBERS; i++) {
-					if(g && g->members[i] && g->members[i]->IsBot() && ((g->members[i]->GetClass() == ENCHANTER) || g->members[i]->GetClass() == CLERIC)) {
+					if(g && g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == ENCHANTER)) {
+						DoesGroupHaveEnchanter = true;
+					}
+				}
+
+				for(int i=0; i<MAX_GROUP_MEMBERS; i++) {
+					//Criimson - seperated cleric and chanter so chanter is primary
+					if(g && g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == ENCHANTER)) {
 						Bot *pacer = g->members[i]->CastToBot();
 						pacer->Say("Trying to pacify %s \n", target->GetCleanName());
 
@@ -11356,12 +11393,29 @@
 							if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm))
 							//if(pacer->IsPacified(target))
 								c->Message(0, "I have successfully pacified %s.", target->GetCleanName());
+								return;
 							/*else
 								c->Message(0, "I failed to pacify %s.", target->GetCleanName());*/
 						}
 						else
 							c->Message(0, "I failed to pacify %s.", target->GetCleanName());
 					}
+					//Criimson - seperated cleric and chanter so chanter is primary
+					if(g && g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == CLERIC) && (DoesGroupHaveEnchanter == false)) {
+						Bot *pacer = g->members[i]->CastToBot();
+						pacer->Say("Trying to pacify %s \n", target->GetCleanName());
+
+						if(pacer->Bot_Command_CalmTarget(target)) {
+							if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_Calm))
+							//if(pacer->IsPacified(target))
+								c->Message(0, "I have successfully pacified %s.", target->GetCleanName());
+								return;
+							/*else
+								c->Message(0, "I failed to pacify %s.", target->GetCleanName());*/
+						}
+						else
+							c->Message(0, "I failed to pacify %s.", target->GetCleanName());
+					}
 					/*else
 						c->Message(15, "You must have an Enchanter or Cleric in your group.");*/
 				}
@@ -13255,7 +13309,8 @@
 
 	int8 botCasterClass = caster->GetClass();
 
-	if( botCasterClass == CLERIC || botCasterClass == DRUID || botCasterClass == SHAMAN || botCasterClass == PALADIN || botCasterClass == BEASTLORD || botCasterClass == RANGER) {
+	//CRIIMSON: Changed so heal based on health percentage is different for hybrids
+	if( botCasterClass == CLERIC || botCasterClass == DRUID || botCasterClass == SHAMAN) {
 		//If AI_EngagedCastCheck() said to the healer that he had to heal
 		if( iSpellTypes == SpellType_Heal )	{
 			// check in group
@@ -13300,6 +13355,52 @@
 		}
 	}
 
+		//CRIIMSON: Changed so heal based on health percentage is different for hybrids
+		if( botCasterClass == PALADIN || botCasterClass == BEASTLORD || botCasterClass == RANGER) {
+		//If AI_EngagedCastCheck() said to the healer that he had to heal
+		if( iSpellTypes == SpellType_Heal )	{
+			// check in group
+			if(caster->HasGroup()) {
+				Group *g = caster->GetGroup();
+				
+				if(g) {
+					for(int i = 0; i < MAX_GROUP_MEMBERS; i++) {
+						if(g->members[i] && !g->members[i]->qglobal) {
+							if(g->members[i]->IsClient() && g->members[i]->GetHPRatio() < 20) {
+								if(caster->AICastSpell(g->members[i], iChance, SpellType_Heal))
+									return true;
+							}
+							else if((g->members[i]->GetClass() ==  WARRIOR || g->members[i]->GetClass() == PALADIN || g->members[i]->GetClass() == SHADOWKNIGHT) &&
+								g->members[i]->GetHPRatio() < 20) 
+							{
+								if(caster->AICastSpell(g->members[i], 100, SpellType_Heal))
+									return true;
+							}
+							else if(g->members[i]->GetClass() ==  ENCHANTER && g->members[i]->GetHPRatio() < 20) {
+								if(caster->AICastSpell(g->members[i], 100, SpellType_Heal))
+									return true;
+							}
+							else if(g->members[i]->GetHPRatio() < 20) {
+								if(caster->AICastSpell(g->members[i], 100, SpellType_Heal))
+									return true;
+							}
+						}
+
+						if(g->members[i] && !g->members[i]->qglobal && g->members[i]->HasPet() && g->members[i]->GetPet()->GetHPRatio() < 20) {
+							if(g->members[i]->GetPet()->GetOwner() != caster && caster->IsEngaged() && g->members[i]->IsCasting() && g->members[i]->GetClass() != ENCHANTER )
+								continue;
+
+							if(caster->AICastSpell(g->members[i]->GetPet(), 100, SpellType_Heal))
+								return true;
+						}
+					}
+				}
+			}
+
+			// TODO: raid heals
+		}
+	}
+	
 	//Ok for the buffs..
 	if( iSpellTypes == SpellType_Buff) {
 		// Let's try to make Bard working...
@@ -13332,6 +13433,7 @@
 	return false;
 }
 
+
 Mob* EntityList::GetMobByBotID(uint32 botID) {
 	Mob* Result = 0;
 
Index: bot.h
===================================================================
--- bot.h	(revision 1958)
+++ bot.h	(working copy)
@@ -292,6 +292,7 @@
 	static bool GroupHasClericClass(Group* group) { return GroupHasClass(group, CLERIC); }
 	static bool GroupHasDruidClass(Group* group) { return GroupHasClass(group, DRUID); }
 	static bool GroupHasShamanClass(Group* group) { return GroupHasClass(group, SHAMAN); }
+	static bool GroupHasEnchanterClass(Group* group) { return GroupHasClass(group, ENCHANTER); }
 	static bool GroupHasPriestClass(Group* group) { return GroupHasClass(group, CLERIC | DRUID | SHAMAN); }
 
 	// "GET" Class Methods
Index: botspellsai.cpp
===================================================================
--- botspellsai.cpp	(revision 1958)
+++ botspellsai.cpp	(working copy)
@@ -253,6 +253,29 @@
 							continue;
 					}
 
+					switch(tar->GetArchetype())
+					{
+						case ARCHETYPE_CASTER:
+							//TODO: probably more caster specific spell effects in here
+							if(IsEffectInSpell(selectedBotSpell.SpellId, SE_AttackSpeed) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ATK) ||
+								 IsEffectInSpell(selectedBotSpell.SpellId, SE_STR) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ReverseDS))
+							{
+								continue;
+							}
+							break;
+						case ARCHETYPE_MELEE:
+							//TODO: Include mana regen (breeze/clarity/etc), I don't know what spell effect it is
+							if(IsEffectInSpell(selectedBotSpell.SpellId, SE_IncreaseSpellHaste) || IsEffectInSpell(selectedBotSpell.SpellId, SE_ManaPool))
+							{
+								continue;
+							}
+							break;
+						case ARCHETYPE_HYBRID:
+							//Hybrids get all buffs
+						default:
+							break;
+					}
+
 					if(CheckSpellRecastTimers(this, itr->SpellIndex))
 					{
 
@@ -297,6 +320,17 @@
 					checked_los = true;
 				}
 
+				if(botClass == CLERIC && this->GetManaRatio() <= 75.0f)
+				{
+					//If we're at 75% mana or below, don't nuke as a cleric or 50% as enchanter
+					break;
+				}
+				if(botClass == ENCHANTER && this->GetManaRatio() <= 50.0f)
+				{
+					//If we're at 75% mana or below, don't nuke as a cleric or 50% as enchanter
+					break;
+				}
+
 				if(botClass == MAGICIAN || botClass == SHADOWKNIGHT || botClass == NECROMANCER || botClass == PALADIN || botClass == RANGER || botClass == DRUID || botClass == CLERIC) {
 					if(tar->GetBodyType() == BT_Undead || tar->GetBodyType() == BT_SummonedUndead || tar->GetBodyType() == BT_Vampire)
 						botSpell = GetBestBotSpellForNukeByTargetType(this, ST_Undead);
@@ -532,16 +566,18 @@
 
 					Mob* addMob = GetFirstIncomingMobToMez(this, botSpell);
 
-					if(!addMob)
-						break;
+					if(!addMob){
+						//Say("!addMob.");
+						break;}
 
 					if(!(!addMob->IsImmuneToSpell(botSpell.SpellId, this) && addMob->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0))
 						break;
 					
 					castedSpell = AIDoSpellCast(botSpell.SpellIndex, addMob, botSpell.ManaCost);
+
 			}
 			break;
-							}
+			}
 		default: {
 			break;
 					  }
@@ -722,6 +758,8 @@
 
 		mlog(AI__SPELLS, "Engaged autocast check triggered (BOTS). Trying to cast healing spells then maybe offensive spells.");
 
+
+
 		if(botClass == CLERIC) {
 			if(!AICastSpell(this, 100, SpellType_Heal)) {
 				if(!entity_list.Bot_AICheckCloseBeneficialSpells(this, 100, BotAISpellRange, SpellType_Heal)) {
@@ -1311,7 +1349,7 @@
 
 		std::list<NPC*> npc_list;
 		entity_list.GetNPCList(npc_list);
-
+		
 		for(std::list<NPC*>::iterator itr = npc_list.begin(); itr != npc_list.end(); itr++) {
 			NPC* npc = *itr;
 
Index: mob.cpp
===================================================================
--- mob.cpp	(revision 1958)
+++ mob.cpp	(working copy)
@@ -672,6 +672,53 @@
 	}
 }
 
+uint8 Mob::GetArchetype() const {
+	switch(class_)
+	{
+	case PALADIN:
+	case RANGER:
+	case SHADOWKNIGHT:
+	case BARD:
+	case BEASTLORD:
+	case PALADINGM:
+	case RANGERGM:
+	case SHADOWKNIGHTGM:
+	case BARDGM:
+	case BEASTLORDGM:
+		return ARCHETYPE_HYBRID;
+		break;
+	case CLERIC:
+	case DRUID:
+	case SHAMAN:
+	case NECROMANCER:
+	case WIZARD:
+	case MAGICIAN:
+	case ENCHANTER:
+	case CLERICGM:
+	case DRUIDGM:
+	case SHAMANGM:
+	case NECROMANCERGM:
+	case WIZARDGM:
+	case MAGICIANGM:
+	case ENCHANTERGM:
+		return ARCHETYPE_CASTER;
+		break;
+	case WARRIOR:
+	case MONK:
+	case ROGUE:
+	case BERSERKER:
+	case WARRIORGM:
+	case MONKGM:
+	case ROGUEGM:
+	case BERSERKERGM:
+		return ARCHETYPE_MELEE;
+		break;
+	default:
+		return ARCHETYPE_HYBRID;
+		break;
+	}
+}
+
 void Mob::CreateSpawnPacket(EQApplicationPacket* app, Mob* ForWho) {
 	app->SetOpcode(OP_NewSpawn);
 	app->size = sizeof(NewSpawn_Struct);
Index: mob.h
===================================================================
--- mob.h	(revision 1958)
+++ mob.h	(working copy)
@@ -52,6 +52,18 @@
 #define CON_YELLOW		15
 #define CON_RED			13
 
+#define APPEAR_HEIGHT	0x001d
+#define	APPEAR_HP_TIC	0x0011
+ 
+#define ARCHETYPE_HYBRID	1
+#define ARCHETYPE_CASTER	2
+#define ARCHETYPE_MELEE		3
+
+#define CON_GREEN		2
+#define CON_LIGHTBLUE	18
+#define CON_BLUE		4
+
+
 //LOS Parameters:
 #define HEAD_POSITION 0.9f	//ratio of GetSize() where NPCs see from
 #define SEE_POSITION 0.5f	//ratio of GetSize() where NPCs try to see for LOS
@@ -669,9 +681,10 @@
 	void			SetZone(int32 zone_id, int32 instance_id);
 
 	// neotokyo: moved from client to use in NPC too
-	char GetCasterClass() const;
-	virtual sint32 CalcMaxMana();
-
+ 	char GetCasterClass() const;
+	uint8 GetArchetype() const;
+ 	virtual sint32 CalcMaxMana();
+ 
 	inline virtual sint16	GetAC()		const { return AC + itembonuses.AC + spellbonuses.AC; } // Quagmire - this is NOT the right math
 	inline virtual sint16	GetATK()	const { return ATK + itembonuses.ATK + spellbonuses.ATK; }
 	inline virtual sint16	GetATKBonus()	const { return itembonuses.ATK + spellbonuses.ATK; }
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 02:11 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