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

Development::Bots Forum for bots.

Reply
 
Thread Tools Display Modes
  #1  
Old 01-02-2014, 04:26 PM
seveianrex
Sarnak
 
Join Date: Sep 2008
Location: asdf
Posts: 60
Default Bot Beg Buff

I found myself having to #findspell and #cast despite having the correct classes of bots in my group, and I wanted a way to make it seem more legitimate....

I don't know how big the appetite for having this would be so I am posting it here and not attempting to commit anything...

The following is some code you can add to your bots.cpp for the ability to beg for buffs from your currently grouped or targetted Bot character.

Syntax:
#bot cast <spell name> [target]

Spell name is wrapped in quotes
Target is an optional keyword to indicate you want the spell casted on your current target.

Examples:
#bot cast Virtue
#bot cast "Spirit of Wolf"
#bot cast "Circle of Great Divide"
#bot cast "Divine Intervention" target

What it does from a programming POV:
Finds the spell, then iterates group members and attempts to find someone whose classes spellbook has it (sufficient level is also checked). If you have an ungrouped bot (which you own) targetted, it will also search that bot's spellbook.

Self-only spells still work self-only, so if you do #bot cast "Illusion: Dark Elf" your enchanter will turn him/herself into a DE....

Future development
- add checks for item clickies from bot inventory
- allowing the pseudo activation of AAs....

Known issues
- if the bot is currently casting it will say "casting" but actually fail.
- if the bot is unable to cast, it will fail but not explain why.

Place this somewhere in the massive list of ifchecks for #bot found in bot.cpp:
Code:
// 2014-01-02 beg for buffs
	// seveian
	if ((!strcasecmp(sep->arg[1], "cast")) && (c->IsGrouped())) {
		Mob *provider;
		Mob *target;
		uint32 providerClass = 0;
		int spell_id = -1;

		Group *g = c->GetGroup();
		if (g) {
			char sName[64];
			char sCriteria[64];

			strcpy(sCriteria, sep->arg[2]);
			strupr(sCriteria);
			for (int i = 0; i < SPDAT_RECORDS; i++) {
				if (spells[i].name[0] != 0 && strlen(spells[i].name) > 1) {
					strcpy(sName, spells[i].name);
					strupr(sName);
					
					if (strcmp(sName, sCriteria) == 0) {
						spell_id = spells[i].id;
						break;
					}
				}
			}
			
			if (spell_id < 1) {
				c->Message(15, "Unable to find any known spell with that name.");
				return;
			}

			target = c->CastToMob();

			if (strcmp(sep->arg[3], "") != 0) {				
				// indicated we want to direct the cast at current target
				// 2014-01-03
				if (strcasecmp(sep->arg[3], "TARGET") == 0) {
					if (c->GetTarget()) {
						target = c->GetTarget()->CastToMob();
					}
				}
			}
			
			// If we have an owned bot targetted, we should also search its spellbook.
			// 2014-01-03
			if (c->GetTarget() && c->GetTarget()->IsBot() && c->GetTarget()->CastToBot()->GetBotOwner() == c) {
				if (spells[spell_id].classes[c->GetTarget()->GetClass() - 1] <= c->GetTarget()->GetLevel()) {
					provider = c->GetTarget()->CastToMob();
					providerClass = c->GetTarget()->GetClass();
				}
			}

			// If we already found a provider, skip the search via group members
			if (providerClass < 1) {
				for (int i = 0; i < MAX_GROUP_MEMBERS; i++) {
					if (g->members[i] && g->members[i]->IsBot()) {
						if (spells[spell_id].classes[g->members[i]->GetClass() - 1] <= g->members[i]->GetLevel()) {
							provider = g->members[i]->CastToMob();
							providerClass = g->members[i]->GetClass();
							break;
						}
					}
				}
			}

			if (providerClass < 1) {
				c->Message(15, "Unfortunately, noone has the ability to cast that spell.");
				return;
			}
			else {
				char temp[100];
				sprintf(temp, "Casting %s on %s...", spells[spell_id].name, target->GetName());
				provider->Say(temp);
				
				provider->CastSpell(spell_id, target->GetID(), 1, -1, -1);
				return;
			}
		}
	}
Reply With Quote
  #2  
Old 01-02-2014, 06:10 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

Wow that's a whole lot of memory leaks. Don't use new if you don't need to.
Reply With Quote
  #3  
Old 01-02-2014, 09:11 PM
seveianrex
Sarnak
 
Join Date: Sep 2008
Location: asdf
Posts: 60
Default

Quote:
Originally Posted by lerxst2112 View Post
Wow that's a whole lot of memory leaks. Don't use new if you don't need to.
Care to elaborate? The only potentially dangerous thing I can see would be the one that iterates the spells list and then strcpys to sName. That is code I copied directly from #findspell however :P Other than that I define 3 chars, most of which are temp for the purposes of sprintf.
Reply With Quote
  #4  
Old 01-02-2014, 08:58 PM
Kingly_Krab
Administrator
 
Join Date: May 2013
Location: United States
Posts: 1,595
Default

Most people prefer a diff format, could you provide that, also, if the code is broken and possibly detrimental due to aforementioned memory leaks, I don't think it's ready for release.
Reply With Quote
  #5  
Old 01-02-2014, 09:19 PM
demonstar55
Demi-God
 
Join Date: Apr 2008
Location: MA
Posts: 1,164
Default

temp, xtmp, and tmp are never deallocated.
Reply With Quote
  #6  
Old 01-02-2014, 09:44 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

Quote:
Originally Posted by demonstar55 View Post
temp, xtmp, and tmp are never deallocated.
xtmp doesn't appear to be used at all, and none of those allocations should be done with new since they are fixed size. Since there are multiple returns in the function it'd be a pain to try and figure out which of them need to be deleted before each return but if they are created on the stack it's automatically handled.

You only need one buffer to construct all of the strings you send to the client, there's no reason to allocate one, use it once, then allocate another one the next time you need to construct a message. The sizes are also rather random, 100, 250, 1000 when you can be pretty sure what the upper bound is since the only argument is the name of the spell and that has a maximum size.
Reply With Quote
  #7  
Old 01-03-2014, 11:08 AM
seveianrex
Sarnak
 
Join Date: Sep 2008
Location: asdf
Posts: 60
Default

Quote:
Originally Posted by lerxst2112 View Post
xtmp doesn't appear to be used at all, and none of those allocations should be done with new since they are fixed size. Since there are multiple returns in the function it'd be a pain to try and figure out which of them need to be deleted before each return but if they are created on the stack it's automatically handled.

You only need one buffer to construct all of the strings you send to the client, there's no reason to allocate one, use it once, then allocate another one the next time you need to construct a message. The sizes are also rather random, 100, 250, 1000 when you can be pretty sure what the upper bound is since the only argument is the name of the spell and that has a maximum size.
Thanks! I have updated the original code to fix some of these issues. Apparently become a little too dependent on my GarbageCollector in C#

As of this morning I have also added functionality to allow you to specify target as a 3rd argument which will have the spell casted on your current target (defaults to you if no target).
Also, if you perform this command with one of your ungrouped bots targetted, it will also search their spellbook and use that bot if found. This allows commanding of "buff bots" outside of your group of bots.
Reply With Quote
  #8  
Old 01-03-2014, 02:48 PM
demonstar55
Demi-God
 
Join Date: Apr 2008
Location: MA
Posts: 1,164
Default

Just a couple things to note:

Having comments like your name/date are rather pointless (we use version control software to keep track of that)

We use strcasecmp to compare strings case insensitively. On Windows this is just defined to stricmp, on UNIX it just uses the libc extension strcasecmp. (so you can replace strupr and strcmp)

And I believe (from quickly looking through the other bot code) that the bots Say function works like printf family does. So Say("Butts %s", spell_name); kind of thing should work (so you can remove the char buffer and call to sprintf, it internally does use a buffer and printf stuff, but it's nicer :P)

I would highly recommend looking into making a pull request on GitHub if you would like to see this included, if setting up GitHub is too much, you can always make a post with a unified diff in the code submissions forum.

This post http://eqemulator.org/forums/showthread.php?t=36515 might help with some git stuff.

Personally, I probably wouldn't pull this since I've never touched the bots stuff so I would leave it up to someone else :P
Reply With Quote
  #9  
Old 01-03-2014, 08:53 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

I usually leave bot code to bad_captain since it's his bailiwick.

I don't mind attempting to fix bugs/errors, but, even that recent out-of-combat bard songs went through him.
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #10  
Old 01-04-2014, 10:01 AM
seveianrex
Sarnak
 
Join Date: Sep 2008
Location: asdf
Posts: 60
Default

Quote:
Originally Posted by Uleat View Post
I usually leave bot code to bad_captain since it's his bailiwick.

I don't mind attempting to fix bugs/errors, but, even that recent out-of-combat bard songs went through him.
makes sense! not looking to step on anyones toes. just thought i would post it in case someone else had the same desire as i!

if the guy who wrote bots would prefer i can delete the post (i think?)
Reply With Quote
  #11  
Old 01-04-2014, 11:26 AM
sorvani
Dragon
 
Join Date: May 2010
Posts: 965
Default

No, you were or told to clean it up and make a pull request so maybe bad_captain will implement it.
Reply With Quote
  #12  
Old 01-04-2014, 08:04 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

Yeah, I didn't mean to discourage you if I came across that way.


But, as far as code making it into repo, that's generally left to fixes and features not yet supported.

Fortunately, bot code isn't restricted to that..so, maybe it will

If nothing else, a working 'patch' will always allow people to use it superfluously
__________________
Uleat of Bertoxxulous

Compilin' Dirty
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 09:44 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