Custom Elite Ranking and Legal Status system from dictionary

An area for discussing new ideas and additions to Oolite.

Moderators: winston, another_commander

Post Reply
User avatar
Pleb
---- E L I T E ----
---- E L I T E ----
Posts: 908
Joined: Sun Apr 29, 2012 2:23 pm
Location: United Kingdom

Custom Elite Ranking and Legal Status system from dictionary

Post by Pleb »

It's been asked a few times on the forums about making the Elite Ranking and Legal Statuses editable via an OXP. I had originally posted up in a different thread how this could be accomplished by adding extra arrays into the descriptions.plist file, but I have now discovered a much easier and tidier way of doing this - by creating a new ratings.plist file and having the data stored in there.

So, let's start at the beginning. First, open the file PlayerEntity.h in the source and go to line 1029 and replace that line with the following:

Code: Select all

NSString *OODisplayStringFromLegalStatus(unsigned legalStatus);
Now open the NSStringOOExtensions.h file and add this at line 61:

Code: Select all

- (NSComparisonResult)oo_compareNumerically:(NSString *)str;
Now open the OOConstToString.h file and add this at line 106:

Code: Select all

NSString *OODisplayRatingsFromNumericalValue(NSString *context, unsigned inputNum);
Now open up the Universe.h file and first insert the following around line 248:

Code: Select all

	NSDictionary			*ratings;				// holds data for the elite rankings and legal status systems
And insert the following at around line 609:

Code: Select all

- (NSDictionary *) ratings;
This takes care of the header files. Now, open the NSStringOOExtensions.m file and add the following at line 151:

Code: Select all

- (NSComparisonResult)oo_compareNumerically:(NSString *)str 
{
	NSNumber * num1 = [NSNumber numberWithInt:[self intValue]];
	NSNumber * num2 = [NSNumber numberWithInt:[str intValue]];

	return [num1 compare:num2];
}
Now open the Universe.m file and first insert the following at around line 352:

Code: Select all

	ratings = [[ResourceManager dictionaryFromFilesNamed:@"ratings.plist" inFolder:@"Config" andMerge:YES] retain];
Then insert the following at around line 431:

Code: Select all

	[ratings release];
Then insert the following at around line 7154:

Code: Select all

- (NSDictionary *) ratings
{
	return ratings;
}
And then insert the following at around line 9863:

Code: Select all

		[ratings autorelease];
		ratings = [[ResourceManager dictionaryFromFilesNamed:@"ratings.plist" inFolder:@"Config" andMerge:YES] retain];
Now open the OOConstToString.m file and go to line 470. Insert the following here (do not replace anything yet, just insert this function):

Code: Select all

NSString *OODisplayRatingsFromNumericalValue(NSString *context, unsigned inputNum)
{
	NSMutableDictionary	*ratingDict = [[NSMutableDictionary alloc] init];
	NSString 			*ratingString;
	NSArray 			*ratingKeys;
	NSMutableArray 		*mutableRatingKeys = [[NSMutableArray alloc] init];
	NSArray 			*sortedRatingKeys;
	unsigned 			i;
	int					numInt;
	BOOL				customStringInvalid;
	NSString			*logKey;
	
	[ratingDict addEntriesFromDictionary:[[UNIVERSE ratings] oo_dictionaryForKey:context]];
	ratingKeys = [ratingDict allKeys];
	customStringInvalid = NO;
	numInt = 0;
	logKey = @"_default";
	
	if ([context isEqualToString:@"rankings"]) logKey = @"new.rankings.error";
	if ([context isEqualToString:@"legal_status"]) logKey = @"new.legal.status.error";
	
	for (i = 0; i < [ratingKeys count]; ++i)
	{
		ratingString = [NSString stringWithFormat:@"%u", [ratingKeys oo_intAtIndex:i]];
		numInt = [ratingString integerValue];
		if (numInt < 0)
		{
			customStringInvalid = YES;
			OOLog(logKey, @"The '%@' dictionary in ratings.plist contains a negative value key - reverting to original system.", context);
			break;
		}
		ratingString = [NSString stringWithFormat:@"%u", [ratingKeys oo_intAtIndex:i]];
		[mutableRatingKeys addObject:ratingString];
	}
	
	sortedRatingKeys = [mutableRatingKeys sortedArrayUsingSelector:@selector(oo_compareNumerically:)];

	if ([sortedRatingKeys oo_unsignedIntAtIndex:0] != 0 && !customStringInvalid)
	{
		customStringInvalid = YES;
		OOLog(logKey, @"The value keys in the '%@' dictionary in ratings.plist do not start at 0 - reverting to original system.", context);
	}
	
	if (!customStringInvalid)
	{
		for (i = 0; i < [sortedRatingKeys count]; ++i)
		{
			if (inputNum < [sortedRatingKeys oo_unsignedIntAtIndex:i])  
			{
				
				ratingString = [NSString stringWithFormat:@"%u", [sortedRatingKeys oo_unsignedIntAtIndex:i-1]];
				if ([ratingDict objectForKey:ratingString] != nil)
				{
					return [ratingDict objectForKey:ratingString];
				}
				else
				{
					customStringInvalid = YES;
					OOLog(logKey, @"'nil' value returned when trying to display %@ - reverting to original system.", context);
					break;
				}
			}
		}
	}
	
	if (customStringInvalid)
	{
		if ([context isEqualToString:@"rankings"])
		{
			enum { kRatingCount = 9 };

			const unsigned	killThresholds[kRatingCount - 1] =
							{
								0x0008,
								0x0010,
								0x0020,
								0x0040,
								0x0080,
								0x0200,
								0x0A00,
								0x1900
							};

			NSString *eliteRating = [NSString stringWithUTF8String:"★★★ E L I T E ★★★"];
			NSString *deadlyRating = [NSString stringWithUTF8String:"☆ Deadly ☆"];
			NSArray *stringArray = [NSArray arrayWithObjects:@"Harmless",@"Mostly Harmless",@"Poor",@"Average",@"Above Average",@"Competent",@"Dangerous",deadlyRating,eliteRating,nil];
			for (i = 0; i < kRatingCount - 1; ++i)
			{
				if (inputNum < killThresholds[i])  return [stringArray oo_stringAtIndex:i];
			}

			return [stringArray oo_stringAtIndex:kRatingCount - 1];
		}
		if ([context isEqualToString:@"legal_status"])
		{
			enum { kStatusCount = 3 };

			const int		statusThresholds[kStatusCount - 1] =
							{
								1,
								51
							};

			NSArray *stringArray = [NSArray arrayWithObjects:@"Clean",@"Offender",@"Fugitive",nil];
			for (i = 0; i != kStatusCount - 1; ++i)
			{
				if (inputNum < statusThresholds[i])  return [stringArray oo_stringAtIndex:i];
			}

			return [stringArray oo_stringAtIndex:kStatusCount - 1];
		}
	}
	
	i = [sortedRatingKeys count] - 1;
	ratingString = [NSString stringWithFormat:@"%u", [sortedRatingKeys oo_unsignedIntAtIndex:i]];
	return [ratingDict objectForKey:ratingString];
}
Now, go to line 589 and replace the section/function there with the following:

Code: Select all

NSString *OODisplayRatingStringFromKillCount(unsigned kills)
{
	NSString *contextType = @"rankings";
	
	return [NSString stringWithFormat:@"%@", OODisplayRatingsFromNumericalValue(contextType, kills)];
}
Go down to line 604 and the replace the section/function there with the following:

Code: Select all

NSString *OODisplayStringFromLegalStatus(unsigned legalStatus)
{
	NSString *contextType = @"legal_status";
	
	return [NSString stringWithFormat:@"%@", OODisplayRatingsFromNumericalValue(contextType, legalStatus)];
}
This takes care of the source files. Now, go to the resources folder and create a new plist file called ratings.plist and make sure it looks like the following:

Code: Select all

{
	"rankings" = 	
	{
		"0" = "Harmless";
		"8" = "Mostly Harmless";
		"16" = "Poor";
		"32" = "Average";
		"64" = "Above Average";
		"128" = "Competent";
		"512" = "Dangerous";
		"2560" = "☆ Deadly ☆";
		"6400" = "★★★ E L I T E ★★★";
	};
	
	"legal_status" = 
	{
		"0" = "Clean";
		"1" = "Offender";
		"51" = "Fugitive";
	};
}
Finally, open up logcontrol.plist and add the following two lines:

Code: Select all

	new.rankings.error						= yes;
	new.legal.status.error					= yes;
And there you have it, a way of creating new elite rankings and legal statuses via a new plist file. The line numbers quoted above may not be exact, but anyone with a small amount of knowledge of the source will be able to figure out what I mean! :lol:

There are limitations, such as they both have to start at 0 and cannot contain negative values (this will cause the game to fall back to the original system, which is now hardcoded). Also, there are certain commands (I'm thinking of the new Priority AI in particular here) that assume there are only three legal statuses. But for all intents and purposes this is how this could be accomplished... :)
Desktop PC: CPU: Intel i7-4790K Quad Core 4.4GHz (Turbo-Charged) GPU: Nvidia GeForce GTX 1080Ti RAM: 32GB DDR3

Laptop PC: CPU: Intel i5-10300H Quad Core 4.5GHz (Turbo-Charged) GPU: Nvidia GeForce GTX 1650 RAM: 32GB DDR4
Zireael
---- E L I T E ----
---- E L I T E ----
Posts: 1396
Joined: Tue Nov 09, 2010 1:44 pm

Re: Custom Elite Ranking and Legal Status system from dictio

Post by Zireael »

I love you, man!
Post Reply