Properties

I changed both forms of remove_property to return the previous value of the property.

string remove_property( string name )

If its a built-in property, resets to default.
Otherwise, removes from the user map.
In either case, return the old value

string remove_property( string name, boolean global )

If its a built-in property, resets to default.
Otherwise, removes from the specified map.
In either case, return the old value

Given that, the following works to migrate a user property from one name to another.

Code:
boolean migrate_property( string old_name, string new_name )
{
    if ( !property_has_default( old_name ) &&
	 !property_has_default( new_name ) &&
	 property_exists( old_name, false ) &&
	 !property_exists( new_name, false ) ) {
	set_property( new_name, remove_property( old_name ) );
	return true;
    }
    return false;
}
Unfortunately, since, as I mentioned, set_property() logs changes to the gCLI, this prints something.

I'm considering making that into a built-in function:

boolean rename_property( string old_name, string new_name )
 
Revision 17892 adds:

boolean [string] get_all_properties( string filter, boolean global )
boolean property_exists( string name )
boolean property_exists( string name, boolean global )
boolean property_has_default( string name )
string property_default_value( string name )
string get_property( string name, boolean global )
string remove_property( string name )
string remove_property( string name, boolean global )
boolean rename_property( string old_name, string new_name )

Here is a utility function to clean up orphaned globals. I could have done this when reading GLOBAL_prefs.txt except said orphpaned globals are necessary when we move a property from global to user, in order to copy the old value to where it will actually be looked for. Therefore, they can't be removed automatically; only after you've migrated all your users with saved preferences.

Code:
since r17892;

void orphaned_global_properties( boolean rem )
{
    foreach name, builtin in get_all_properties( "", true ) {
	if ( !builtin ) {
	    if ( rem ) {
		print( "removing orphaned global property: " + name );
		remove_property( name, true );
	    } else {
		print( "orphaned global property: " + name );
	    }
	}
    }
}
 
I cleaned up my GLOBAL properties with this little script:

Code:
void orphaned_global_properties( boolean rem )
{
    foreach name, builtin in get_all_properties( "", true ) {
	if ( !builtin ) {
	    if ( rem ) {
		print( "removing orphaned global property: " + name );
		remove_property( name, true );
	    } else {
		print( "orphaned global property: " + name );
	    }
	}
    }
}
Worked like a charm. I then identified my custom user properties with this script:

Code:
void custom_user_properties()
{
    foreach name, builtin in get_all_properties( "", false ) {
	if ( !builtin ) {
	    print( "custom user property: " + name );
	}
    }
}
and selected from it the ones I didn't want, and ran this:

Code:
boolean [string] obsolete_user_props = $strings[
alwaysPromptAboutCrafting,
ascensionrewards.txt,
autostartGalaktikQuest,
availableBoneChips,
availableCRIMBCOScrip,
availableCommendations,
availableCrimbux,
availableIsotopes,
availableLucre,
availableMrAccessories,
availableSandDollar,
availableSandDollars,
availableSnackVouchers,
availableTickets,
...];

void obsolete_user_properties()
{
    foreach name in obsolete_user_props {
	if ( property_exists( name, false ) ) {
	    print( "removing obsolete user property: " + name );
	    remove_property( name, false );
	}
    }
}
Again, worked like a charm. Now, custom_user_properties() returns this:

Code:
[color=green]> ash import <prop_utils.ash>;custom_user_properties()[/color]

custom user property: _snowglobeDrops
custom user property: AdventureFrame
custom user property: AnnouncementFrame
custom user property: BuffRequestFrame
custom user property: CakeArenaFrame
custom user property: CalendarFrame
custom user property: CharSheetFrame
custom user property: ClanManageFrame
custom user property: CoinmastersFrame
custom user property: CommandDisplayFrame
custom user property: ContactListFrame
custom user property: CouncilFrame
custom user property: DatabaseFrame
custom user property: DescriptionFrame
custom user property: EventsFrame
custom user property: ExamineItemsFrame
custom user property: FamiliarTrainingFrame
custom user property: FaxRequestFrame
custom user property: FightFrame
custom user property: FlowerHunterFrame
custom user property: GearChangeFrame
custom user property: ItemManageFrame
custom user property: KoLDesktop
custom user property: LoginFrame
custom user property: MailboxFrame
custom user property: MallSearchFrame
custom user property: MaximizerFrame
custom user property: MeatManageFrame
custom user property: MuseumFrame
custom user property: MushroomFrame
custom user property: OptionsFrame
custom user property: PeeVPeeFrame
custom user property: ProfileFrame
custom user property: RecentEventsFrame
custom user property: RequestFrame
custom user property: RequestSynchFrame
custom user property: ScriptManageFrame
custom user property: SendMessageFrame
custom user property: SkillBuffFrame
custom user property: StoreManageFrame
custom user property: SynthesizeFrame
custom user property: TabbedChatFrame
custom user property: TrophyFrame
custom user property: VMF.TotalMeat
custom user property: VMF.TotalTurns
Returned: void
VMF.xxx are statistics from "Veracity Meat Farm".
_snowglobeDrops is built-in, but not in defaults.txt. Oops. Will fix.
And the XXXFrame and KoLDesktop properties are created by KoLmafia to store details of each frame you've opened so it can restore them to have the previous appearance.

Just as choiceAdventureXXX and skillBurnXXX, those need to be marked as built-in, since I don't feel like adding a default everytime we add a new Frame - especially since we have a list of Frame class names.

More work...
 
Revision 17896 does that.

Here are some updates useful functions:

Code:
void custom_user_properties()
{
    foreach name, builtin in get_all_properties( "", false ) {
	if ( !builtin ) {
	    print( name + "," );
	}
    }
}

boolean [string] obsolete_user_props = $strings[
EventsFrame,
ExamineItemsFrame,
FightFrame,
FlowerHunterFrame,
MailboxFrame,
PeeVPeeFrame,
RecentEventsFrame];

void obsolete_user_properties()
{
    foreach name in obsolete_user_props {
	if ( property_exists( name, false ) ) {
	    print( "removing obsolete user property: " + name );
	    remove_property( name, false );
	}
    }
}
 
One more comment.

Several of my characters had the following properties:

CharSheetFrame
CharsheetFrame

The second one is obsolete. Yet, since get_all_properties() returns a case-insensitive map, it only received one of those - the first.

Interestingly, Preferences.java keeps a map from String to String of the lower_cased name to actual name and exposes it in this method:

Code:
	public static final String getCaseSensitiveName( final String name )
	{
		String lowercase = name.toLowerCase();
		String actualName = Preferences.propertyNames.get( lowercase );

		if ( actualName != null )
		{
			return actualName;
		}

		Preferences.propertyNames.put( lowercase, name );
		return name;
	}
That method is never called. It looks like somebody started to make properties case-insensitive (although allowing them to be stored with whatever case desired, whether in defaults.txt or created by users).

That's a pity. Makes me think get_all_properties should NOT return a case-insensitive map, even though that does make all the properties sort in a useful order.

I'll try that and see how rampant properties whose name differ only in case are in my settings.
 
Just one: I had questG08Moxie and QuestG08Moxie. Only the first was correct.

Revision 17897 no longer returns a case insensitive map from get_all_properties().
(The ability to have that was new ASH technology. Perhaps it will useful in the future.)
 
Very nice. I am looking forward to seeing the various functions outlined in vproperties.

I was curious about testing case sensitivity so I tried something out and saw an odd return value:

Code:
> get setAutoAttack

false

> ash remove_property("setautoattack", false)

Returned:

> get setAutoAttack

false

> ash remove_property("setAutoAttack", false)

Returned: false

remove_property() returned nothing when it failed and false when it worked. Huh?
 
Please correct me if I am wrong, but I think there are some properties not in defaults.txt that I believe are used by KoLmafia and hence, should be present:

  • discardedKarma
  • hermitHax0red
  • lastSpookyravenLightsOut
  • mayoWhipRented

That fits with it returning the previous value (as a string).

Thank you for the correction!
 
Really? Then we have no way of knowing if the mayo Whip was already rented? Or is there another property to tell us if it is in the store? Similarly, is there any way to know if the hermit was haxored.

Perhaps that isn't needed since the only serious result is that there are more ten leaf clovers in his shop.

In retrospect it is obvious that last spookyraven lights out was removed from the code shortly after being added. I'm not sure about discarded karma needing to be recorded.
 
I assume the miracle whip is tracked in itemBoughtPerAscension8266.
I don't know about the hermit.
And the next spookyraven lights out can be calculated by turn number
 
itemBoughtPerAscension8266! Of course! Now I know why the preference was changed.

I figured out the spookyraven lights myself. The old pref was in the code for a very short time before the mechanism was properly understood.

Thank you!
 
If you hack the hermit, we add one to the number of clovers currently available. Subsequent days, we won't know how many are there until we visit.
 
Looking splendid. Thanks for your work Veracity.

I believe with the advent of settings-cleaning utility scripts, there may finally be a defensible use for user_confirm()! Haha
 
zarqon would be correct if only there wasn't such a thing as relay UI scripts. Sorry, zarqon. relay UI scripts were written specifically to get around any possible argument for user_confirm().

I envision a lot of checkboxes next to custom property names to indicate which you want to delete.
 
Heh. For something you will run maybe once a year, it's nice to not bother with presentation. You may recall I once argued against its having any purpose, but this use is actually justifiable in my mind.

That said, I do believe I will spin up a relay script for this. These days the scripts I spend the most time on are all relay scripts.
 
Using custom and obsolete user property code from here, I get a list of custom props, remove some of them and then get the list of custom props again. Some of the things I thought were removed appear.

Is this:

  1. Operator error?
  2. Candidates for built in properties that have been previously missed?
  3. Some kind of cache that is not invalidated when a property is removed?
  4. Script error?
  5. Something that I can't figure out but greater minds than mine can?

If 2 above is most likely I'll post the items othewrise I will try and narrow things down in a repeatable way, but since I am lazy I figured I'd ask first.

Thanks.
 
Back
Top