12 May 2018 Tagged: eulorac++

With a successful build from source it was time for a closer look at that foxybot code. The actual chronology of my code changes I would liken to a drunken walk down a narrow alley with an unfamiliar game world as a brick wall on one side and an unfamiliar codebase on the other. I stubbed my toe on things and did my best to stumble past them. I didn’t actually know much about how the bot was supposed to behave. I knew how to build tiny claims myself (manually), I knew I was sick of clicking and I knew there was a bot.

At this point I just wanted to get it to work. What follows are the minimum changes I needed to make to get it to work for me.

Parse the Item Name Correctly

So as I mentioned before, it seemed like there was an easy fix to my motivating bot problem: replace a single character in the message parsing code. I made that change but it did not fix the problem.

        else if (text.StartsWith(CLAIM_PLACED))
                exploreFinished = true;
                noBuild = false;
-               size_t end = text.FindLast('!');
+               size_t end = text.FindLast('.'); (1)
                size_t start = CLAIM_PLACED.Length();
                csString thingName = text.Slice(start, end-start-1); (2)
                if (thingName.StartsWith("Tiny"))
                        claimType = csString("Tiny");
                else if (thingName.StartsWith("Small"))
                        claimType = csString("Small");
                else claimType = csString("Unknown");

                claimName = thingName;

                //and get the item name too if we are at it
                end = claimName.Find(" Exploration Marker"); (3)
                start = claimType.Length()+1;
                size_t length = end - start;
                itemName = claimName.Slice(start, length);
1 My edit
2 thingName declared
3 itemName parsing

I looked at that parsing code some more and I came to see that the thingName shown above was later used to find the itemName which needed to be correct for the bot to build the claim. This code, when parsing a message such as:

Eulora Dig Message
You placed an Tiny Rickety Reeds Exploration Marker.

assigned a value to thingName such as:

Tiny Rickety Reeds Exploration Marke

which led to the itemName being assigned:

Rickety Reeds Exploration Marke

So there was an off by one issue at the end of the string. There also happens to be a -1 at the end of the thingName assignment line. I deleted it and sure enough the value assigned to thingName recieved it’s proper final letter and itemName parses out to:

Rickety Reeds

Success? No. The bot still locks the claim instead of building it.

Find the Build Item

Ok, so I take a stroll to the code where all that claim locking shit is going down and I notice that the item required to build the claim is not being found, eventhough I have it in my inventory. The FindItemSlot method is being passed a value of false for anywhere. Well I’m not aware of the full implications of this, but at this point I’m ready to 'look anywhere', so I make it true:

-		psInventoryCache::CachedItemDescription* from = worldHandler::FindItemSlot(item, false);
+		psInventoryCache::CachedItemDescription* from = worldHandler::FindItemSlot(item, true);

		if (!from || from->stackCount < quantity)
			//not enough items to build claim, so just move on (don't lock tinies and smalls!!!)
			Notify1(LOG_USER, "will go on");
			noBuild = true;
			return true;

But still it’s not working.

Equip the Scroll Correctly

Now it is failing to equip the scroll. The code looks like this:

if (!worldHandler::IsInBrain(scrollName))               (1)
        if (!worldHandler::EquipRecipe(scrollName))     (2)
                        OutputMsg(csString("Missing blueprint for the claim!"));
                        //noBuild = true;
            return false;
1 test if it’s equipped
2 equip it

I know something’s wrong here immediately because that missing blueprint message has never displayed. Testing this out reveals that IsInBrain always returns false, even when it’s equipped, and that EquipRecipe always returns true, eventhough it’s failing. So Let’s fix them one at a time:

bool worldHandler::IsInBrain(csString itemName)
	pawsSlot* slot = FindInventoryItemSlot(itemName);
	if (slot == NULL)
		return false;
		return (slot->GetID() == PSCHARACTER_SLOT_MIND);

Well I’ve already had a run in with a different Find method, so I’m suspicious of this one. I noticed this worldhandler class has a method called GetBrainItemName. Seems to me this whole thing can be a one liner:

bool worldHandler::IsInBrain(csString itemName)
    return GetBrainItemName() == itemName;

I took it for a spin and IsInBrain is now working correctly: returning false only when the scroll is actually missing. One down, one more to go. So I moved on the the actual equipping method.

I saw that EquipRecipe contains an additional check so that the equip will be attempted 'only if truly needed', as the comment says. I don’t know about all that, if I call EquipRecipe I damn well want it equipped. I decided to just comment out that test.

bool worldHandler::EquipRecipe(csString itemName)
	psInventoryCache::CachedItemDescription* slot = FindItemSlot(itemName, true);
	if (slot == NULL)
		return false;

-	if (slot->containerID != CONTAINER_INVENTORY_EQUIPMENT) //equip only if truly needed
+	//if (slot->containerID != CONTAINER_INVENTORY_EQUIPMENT) //equip only if truly needed
		MoveItems(slot->containerID, slot->slot, CONTAINER_INVENTORY_EQUIPMENT, PSCHARACTER_SLOT_MIND, slot->stackCount);

	return true;

Aaaaaaand…​ SHAZAM! We have lift-off. Foxybot’s jukin' and jivin' and building those claims. Make me dat money, daddy’s gotta make a livin'!

Diana Coman - 2018-05-19 07:27:25

Bwahaha, those are fun to read. Foxybot has indeed all sorts of warts and what-nots due to its already-longish history of having to put up with a rather idiotic "protocol" + all sorts of changes. I guess a little bit of history might even give some ideas what these are: http://www.dianacoman.com/2016/09/18/happy-1st-anniversary-foxybot/

At any rate, it’s meant to be changed and beaten into useful shape, so keep at it!

Mocky - 2018-05-19 12:18:13

Oh hey, thank you.

wyrdmantis - 2018-05-27 11:14:26

Hi Mocky, many thanks for this. But for me it’s not working. i’m getting:

src/client/foxybot/botactivity.cpp: In member function ‘void ExploreActivity::DoUseCombine()’:
src/client/foxybot/botactivity.cpp:569:39: error: no matching function for call to ‘csHash<EID, EID>::Put(EID&, csVector3&)’
src/client/foxybot/botactivity.cpp:569:39: note: candidate is:
In file included from /home/wyrdmantis/dev/cs-forupload/include/csutil/strhash.h:23:0,
                 from /home/wyrdmantis/dev/cs-forupload/include/csutil/strhashr.h:23,
                 from ./src/client/psengine.h:23,
                 from ./src/client/globals.h:26,
                 from src/client/foxybot/botactivity.cpp:10:

Maybe it’s a trivial error but i know nothing about C++, also i’m on Ubuntu.

Mocky - 2018-05-28 00:25:46


i think this comment was meant for Foxybot Enhancements Part 1 since there’s no spentClaims in this post.

In that post:

  1. spentClaims.Put does not have markerPos as an argument. Perhaps you typed it in wrong.

  2. spentClaims.Put is not within 100 lines of where your compiler error is. Perhaps you put things in a different place.

Maybe have a closer look at those things.

Also, don’t let the fact that you know nothing about C++ stop you, I don’t.

wyrdmantis - 2018-05-30 15:23:26

LOL markerPOS instead of markerID. My damn eyes…​ Anyway, now works! Thanks, mate!

Mocky - 2018-06-01 04:04:03

Hey, nice to see it works for you.

Add a Comment