PDA

View Full Version : Bot Beg Buff


seveianrex
01-02-2014, 04:26 PM
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:

// 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;
}
}
}

lerxst2112
01-02-2014, 06:10 PM
Wow that's a whole lot of memory leaks. Don't use new if you don't need to.

Kingly_Krab
01-02-2014, 08:58 PM
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.

seveianrex
01-02-2014, 09:11 PM
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.

demonstar55
01-02-2014, 09:19 PM
temp, xtmp, and tmp are never deallocated.

lerxst2112
01-02-2014, 09:44 PM
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.

seveianrex
01-03-2014, 11:08 AM
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.

demonstar55
01-03-2014, 02:48 PM
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

Uleat
01-03-2014, 08:53 PM
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.

seveianrex
01-04-2014, 10:01 AM
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?)

sorvani
01-04-2014, 11:26 AM
No, you were or told to clean it up and make a pull request so maybe bad_captain will implement it.

Uleat
01-04-2014, 08:04 PM
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 :)