Bug - Fixed Garden harvesting issues on login

antimarty

Member
I would like to be able to have my char that has only peppermints harvest them daily, while my char with skeletons lets them pile up to make a skulldozer. It would be nice if the preferences choice for what to do with the garden (After Ronin - "Harvest Anything" "Harvest Nothing" etc) were a per-character choice, but it's a global.

So I've set it to "peppermint sprout" in hopes that it would harvest peppermints, and leave anything else alone, but it harvests my skeletons anyway. Seems like a bug.
 

Veracity

Developer
Staff member
I have exactly the same problem: a character with peppermints wants to harvest them, a character with skeletons wants to get skulldozers. I, too, had to turn off garden harvesting in breakfast to keep the skeletons from being harvested when I have "harvest peppermints" selected.
 

Theraze

Active member
Is this an argument for making breakfast entries per-character rather than global? It means not being able to change them (without editing the text files) before logging in, but it does answer this question as well as libram summoning and other such bits.
 

Veracity

Developer
Staff member
It is a bug that "harvest peppermints" will also harvest skeletons. I don't know if having per-user breakfast settings is otherwise necessary.
 

Bale

Minion
This is why I am handling garden harvesting in my loginScript. I want to pick skeletons every day in ronin, but not in aftercore. But peppermints and pumpkins get picked regardless.

PHP:
boolean pick() {
	matcher garden = create_matcher("action=garden.+?(pumpkinpatch|pepperpatch|bonegarden)_?(\\d)?(.*?)\\.gif", visit_url("campground.php"));
	if(find(garden))
		switch(garden.group(1)) {
		case "pumpkinpatch":
		case "pepperpatch":
			return true;
		case "bonegarden":
			if(!can_interact() && garden.group(2) != "") return true;
			if(garden.group(3) == "spoilzlul")
				print("OMG! There is a Humongous Skull in the garden?! It looks DANGEROUS!", "red");
			return false;
		}
	return false;
}

And a little bit later, set up to only execute on my first login of the day...

PHP:
		if(pick()) cli_execute("garden pick");
 
Last edited:

Catch-22

Active member
The bug is because a skeleton is considered a "better" crop than the peppermint sprout.

The crop should probably only be considered "better" if it's grown in the same patch as the desired item, but just takes longer to mature. For example, if your desired crop is peppermint sprouts but there was a giant candy cane there instead, KoLmafia should still harvest it, or you'll never get your desired crop.

If your desired crop is peppermint sprouts but there's a skeleton there, well.. You'll never get your desired crop until you change your garden, so I guess KoLmafia should ignore it.

I think there's valid argument for a per character preference here.
 

Catch-22

Active member
Eh I had a quick look. I feel like the garden type could be a property of KoLCharacter (ie. that KoLmafia would know about what garden it has internally), with the possibility of exposing that property to the user, if there was a desire to do so.

Once we know the garden type, it's pretty easy to determine what the "better crop" should be for the given garden type.

We can determine the garden type by simply looking at what getCrop() returns, but I think it starts to look a little messy. Thoughts?

It would be nice if whatever gets implemented reduces ongoing code maintenance for future seed packets.
 

Theraze

Active member
Would it make more sense to offer an option for which level you'd like to harvest each crop? Or is that no better, because of cases like Bale's where it varies by in run or aftercore?
 

Catch-22

Active member
Would it make more sense to offer an option for which level you'd like to harvest each crop? Or is that no better, because of cases like Bale's where it varies by in run or aftercore?

Level is a little bit of an ambiguous term, if you are talking about how mature the crop is, you can already do that. It's just that "crops" are all lumped together as a big group, and skeletons are considered a better crop than, say, even a Ginormous Pumpkin.

The simplest change would be to reorder the list so "skeletons" aren't considered better than "peppermint sprouts", but it wouldn't satisfy every case.

Currently, here's the order:
PUMPKIN, HUGE_PUMPKIN, GINORMOUS_PUMPKIN, PEPPERMINT_SPROUT, GIANT_CANDY_CANE, SKELETON

Basically, if something appears later in the order, it's considered "better", so a skeleton, is currently better than any other crop.

You could reorder the list like so:
SKELETON, PEPPERMINT_SPROUT, PUMPKIN, GIANT_CANDY_CANE, HUGE_PUMPKIN, GINORMOUS_PUMPKIN

Which would probably satisfy most desires.
 
Last edited:

lostcalpolydude

Developer
Staff member
Just use get_campground() to see what you have planted, no server hit needed if you are using a script there.

The breakfast harvest code should be changed though.
 

nworbetan

Member
I have my breakfast script set up to only harvest what it's been given permission to harvest:
Code:
int [item] cg = get_campground();
boolean [item] pickit;
/*4761*/ pickit [$item[pumpkin]] = false;
/*4762*/ pickit [$item[huge pumpkin]] = true;
/*4771*/ pickit [$item[ginormous pumpkin]] = true;
/*5395*/ pickit [$item[peppermint sprout]] = true;
/*5402*/ pickit [$item[giant candy cane]] = true;
foreach i in $ints[4761, 4762, 4771, 5395, 5402] if (cg[i.to_item()] > 0 && pickit[i.to_item()]) {
    visit_url("campground.php?action=garden");
    break;
}
 

Bale

Minion
Hrmmn... Maybe I should use the following...

PHP:
boolean pick() {
	foreach c,q in get_campground()
		switch(c) {
		case $item[pumpkin]:
		case $item[huge pumpkin]:
		case $item[ginormous pumpkin]:
		case $item[peppermint sprout]:
		case $item[giant candy cane]:
			return q > 0;
		case $item[skeleton]:
			return q > 0 && !can_interact();
		case $item[skulldozer egg]:
			print("OMG! There is a Humongous Skull in the garden?! It looks DANGEROUS!", "red");
			return false;
		}
	return false;
}
if(pick()) cli_execute("garden pick");
 
Last edited:

lostcalpolydude

Developer
Staff member
The skulldozer is actually reported as -1 skeleton. I believe it's impossible to tell mafia to start that fight except with visit_url().
 

Bale

Minion
The skulldozer is actually reported as -1 skeleton. I believe it's impossible to tell mafia to start that fight except with visit_url().

I was not going to guess that. Thanx. That actually makes the function simpler.

PHP:
boolean pick() {
	foreach c,q in get_campground()
		switch(c) {
		case $item[pumpkin]:
		case $item[huge pumpkin]:
		case $item[ginormous pumpkin]:
		case $item[peppermint sprout]:
		case $item[giant candy cane]:
			return q > 0;
		case $item[skeleton]:
			if(q < 0) print("OMG! There is a Humongous Skull in the garden?! It looks DANGEROUS!", "red");
			return q > 0 && !can_interact();
		}
	return false;
}
if(pick()) cli_execute("garden pick");
 

roippi

Developer
Something like this might work?

Code:
Index: src/net/sourceforge/kolmafia/request/CampgroundRequest.java
===================================================================
--- src/net/sourceforge/kolmafia/request/CampgroundRequest.java	(revision 11734)
+++ src/net/sourceforge/kolmafia/request/CampgroundRequest.java	(working copy)
@@ -33,6 +33,7 @@
 
 package net.sourceforge.kolmafia.request;
 
+import java.util.HashMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -141,6 +142,31 @@
 	public static final AdventureResult GIANT_CANDY_CANE = ItemPool.get( ItemPool.GIANT_CANDY_CANE, 1 );
 	public static final AdventureResult SKELETON = ItemPool.get( ItemPool.SKELETON, 1 );
 
+	private enum CropType
+	{
+		PUMPKIN, 
+		PEPPERMINT, 
+		SKELETON;
+
+		@Override
+		public String toString()
+		{
+			return this.name().toLowerCase();
+		}
+	}
+
+	private static final HashMap<AdventureResult, CropType> CROPMAP = new HashMap<AdventureResult, CropType>();
+
+	static
+	{
+		CROPMAP.put( PUMPKIN, CropType.PUMPKIN );
+		CROPMAP.put( HUGE_PUMPKIN, CropType.PUMPKIN );
+		CROPMAP.put( GINORMOUS_PUMPKIN, CropType.PUMPKIN );
+		CROPMAP.put( PEPPERMINT_SPROUT, CropType.PEPPERMINT );
+		CROPMAP.put( GIANT_CANDY_CANE, CropType.PEPPERMINT );
+		CROPMAP.put( SKELETON, CropType.SKELETON );
+	}
+
 	public static final AdventureResult [] CROPS =
 	{
 		CampgroundRequest.PUMPKIN,
@@ -238,12 +264,6 @@
 		return i != -1 ? (AdventureResult)KoLConstants.campground.get( i ) : null;
 	}
 
-	public static boolean hasCrop( final String crop )
-	{
-		int i = CampgroundRequest.getCropIndex();
-		return i != -1 && crop.equals( ((AdventureResult)KoLConstants.campground.get( i )).getName() );
-	}
-
 	public static boolean hasCropOrBetter( final String crop )
 	{
 		// Get current crop, if any
@@ -279,10 +299,10 @@
 				return false;
 			}
 			// We found the desired crop before we found the
-			// current crop - which must be better. Cool.
+			// current crop - which is therefore better IFF its type is the same.
 			if ( cropName.equals( crop ) )
 			{
-				return true;
+				return CROPMAP.get( CROPS[ i ] ) == CROPMAP.get( current );
 			}
 		}

I won't be able to test for a little while, and it's enough of a hack that I don't trust the logic to be correct without a test or two. I'd like to tear the whole class down and rebuild it all so the code is easier to follow/more maintainable, but I don't have the motivation.
 

Catch-22

Active member
I rebuilt a lot of this class in my own repo but ran out of time late last year and haven't picked it up again. I don't think your solution is too bad anyway.

Maybe some day I'll polish mine up and submit it, but it would only really help in reducing the amount of code it takes to support new garden types (and it parses the campground a little faster, too).
 
Top