Source Code and Ideas question
Moderators: winston, another_commander
Re: Source Code and Ideas question
I don't know anything about Objective-C, but it seems that you need to pass a custom selector in order to get the sort order you want. The one you use compares according to lexical order. I think you have to define a function or method that converts arguments into integers and return the comparison of those integers.
Another possible method is to pad the numeric values with leading zeros before sorting the array so that they have the same, fixed length (or maybe require that they are written that way in a comment). In this case, sorting by lexical order should work.
Storing things as strings when they actually are of some other type (here integer) is not very good practice in terms of programming. Besides this sorting problem, it will likely cause other problems, like the fact that if someone makes a typo (like "O512", a letter 'O' instead of the figure '0') it will likely screw up your program. But I guess there are other constrains forcing you to do it that way that I ignore.
Another possible method is to pad the numeric values with leading zeros before sorting the array so that they have the same, fixed length (or maybe require that they are written that way in a comment). In this case, sorting by lexical order should work.
Storing things as strings when they actually are of some other type (here integer) is not very good practice in terms of programming. Besides this sorting problem, it will likely cause other problems, like the fact that if someone makes a typo (like "O512", a letter 'O' instead of the figure '0') it will likely screw up your program. But I guess there are other constrains forcing you to do it that way that I ignore.
- Diziet Sma
- ---- E L I T E ----
- Posts: 6312
- Joined: Mon Apr 06, 2009 12:20 pm
- Location: Aboard the Pitviper S.E. "Blackwidow"
Re: Source Code and Ideas question
There are also a number of different sorting algorithms around, some of them rather famous in programming circles, designed for different requirements.. it will be worth your while to research them.. a google-search on "sorting algorithms" will get you started.
Most games have some sort of paddling-pool-and-water-wings beginning to ease you in: Oolite takes the rather more Darwinian approach of heaving you straight into the ocean, often with a brick or two in your pockets for luck. ~ Disembodied
- JensAyton
- Grand Admiral Emeritus
- Posts: 6657
- Joined: Sat Apr 02, 2005 2:43 pm
- Location: Sweden
- Contact:
Re: Source Code and Ideas question
Please ignore this advice. :-) You really don’t want to be implementing your own sorting algorithm here.Diziet Sma wrote:There are also a number of different sorting algorithms around, some of them rather famous in programming circles, designed for different requirements.. it will be worth your while to research them.. a google-search on "sorting algorithms" will get you started.
sortedArrayUsingSelector:@selector(compare:)
would be correct if you had an array of NSNumber
s, but what you have is NSString
s.Instead, add a method like this in
NSStringOOExtensions.m
:
Code: Select all
- (NSInteger)oo_compareNumerically:(NSString *)other
{
return [self compare:other options:NSNumericSearch];
}
sortedArrayUsingSelector:@selector(oo_compareNumerically:)
.E-mail: [email protected]
- Diziet Sma
- ---- E L I T E ----
- Posts: 6312
- Joined: Mon Apr 06, 2009 12:20 pm
- Location: Aboard the Pitviper S.E. "Blackwidow"
Re: Source Code and Ideas question
Heh.. I stand corrected.
(I still maintain any coder should study sorting algorithms anyway.. it's a fundamental part of learning to program)
(I still maintain any coder should study sorting algorithms anyway.. it's a fundamental part of learning to program)
Most games have some sort of paddling-pool-and-water-wings beginning to ease you in: Oolite takes the rather more Darwinian approach of heaving you straight into the ocean, often with a brick or two in your pockets for luck. ~ Disembodied
Re: Source Code and Ideas question
Just a minor point, but the figure of 126 has crept into the (non-hex) arrays for the competent rating - it should be 128.
Re: Source Code and Ideas question
I've tried implementing this but it still puts it in a weird order. However I didn't realise these were NSString values and not NSInteger values before, so I will do some more researching to see if this is possible another way. Thank you though!JensAyton wrote:sortedArrayUsingSelector:@selector(compare:)
would be correct if you had an array ofNSNumber
s, but what you have isNSString
s.
Instead, add a method like this inNSStringOOExtensions.m
:Then useCode: Select all
- (NSInteger)oo_compareNumerically:(NSString *)other { return [self compare:other options:NSNumericSearch]; }
sortedArrayUsingSelector:@selector(oo_compareNumerically:)
.
Thanks for pointing this out, not sure where 126 came from! I've fixed in my code now.JD wrote:Just a minor point, but the figure of 126 has crept into the (non-hex) arrays for the competent rating - it should be 128.
Another thing I've noticed was that the ☆ and ★ characters I have hardcoded do not display properly when reverting to the hardcoded ratings system...
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
Laptop PC: CPU: Intel i5-10300H Quad Core 4.5GHz (Turbo-Charged) GPU: Nvidia GeForce GTX 1650 RAM: 32GB DDR4
Re: Source Code and Ideas question
Okay, building upon what JensAyton said about the values in the array being NSString, I've managed to cobble together a comparison method by modifying one used for putting numbers in strings in reverse order (I then reversed this so it goes the way I want it to): This now puts the numbers in the right order. So this fixes the issue of OXP writers putting values in the Being able to sort the arrays means that, in theory, loading a dictionary should now be possible. However because it does not appear to be OXP-friendly I am not sure it's the right direction (although if it were possible it would look tidier)...
EDIT: So...things still left to fix:
Code: Select all
- (NSComparisonResult)oo_compareNumerically:(NSString *)str {
NSNumber * num1 = [NSNumber numberWithInt:[self intValue]];
NSNumber * num2 = [NSNumber numberWithInt:[str intValue]];
return [num1 compare:num2];
}
oolite_rating_kills
and oolite_legal_status_bounty
arrays in non-numerical order. However if you swap the first two values on both the oolite_rating_kills
and oolite_rating_names
arrays, it will show the first rank as "Mostly Harmless" instead of "Harmless". So you'd still need the values in the oolite_rating_names
and oolite_legal_status_names
arrays to be in the right order. Code: Select all
NSString *OODisplayRatingStringFromKillCount(unsigned kills)
{
NSArray *ratingNames = nil;
NSArray *ratingKills = nil;
NSArray *sortedRatingKills = nil;
unsigned i;
BOOL newRatingsInvalid;
ratingNames = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_rating_names"];
ratingKills = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_rating_kills"];
sortedRatingKills = [ratingKills sortedArrayUsingSelector:@selector(oo_compareNumerically:)];
newRatingsInvalid = NO;
if ([ratingNames count] != [sortedRatingKills count])
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'oolite_rating_kills' and 'oolite_rating_names' array size in descriptions.plist not equal - reverting to original ratings system.");
}
if ([sortedRatingKills oo_unsignedIntAtIndex:0] != 0)
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'oolite_rating_kills' array in descriptions.plist does not start at 0 - reverting to original ratings system.");
}
if (!newRatingsInvalid)
{
for (i = 0; i < [sortedRatingKills count]; ++i)
{
if (kills < [sortedRatingKills oo_unsignedIntAtIndex:i])
{
if ([ratingNames oo_stringAtIndex:i-1] != nil)
{
return [ratingNames oo_stringAtIndex:i-1];
}
else
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'nil' value returned when trying to display rating status - reverting to original ratings system.");
break;
}
}
}
}
if (newRatingsInvalid)
{
enum { kRatingCount = 9 };
const unsigned killThresholds[kRatingCount - 1] =
{
0x0008,
0x0010,
0x0020,
0x0040,
0x0080,
0x0200,
0x0A00,
0x1900
};
ratingNames = [NSArray arrayWithObjects:@"Harmless",@"Mostly Harmless",@"Poor",@"Average",@"Above Average",@"Competent",@"Dangerous",@"☆ Deadly ☆",@"★★★ E L I T E ★★★",nil];
for (i = 0; i < kRatingCount - 1; ++i)
{
if (kills < killThresholds[i]) return [ratingNames oo_stringAtIndex:i];
}
return [ratingNames oo_stringAtIndex:kRatingCount - 1];
}
return [ratingNames oo_stringAtIndex:[sortedRatingKills count] - 1];
}
Code: Select all
NSString *OODisplayStringFromLegalStatus(int legalStatus)
{
NSArray *statusNames = nil;
NSArray *statusBounty = nil;
NSArray *sortedStatusBounty = nil;
unsigned i;
BOOL newStatusInvalid;
statusNames = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_legal_status_names"];
statusBounty = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_legal_status_bounty"];
sortedStatusBounty = [statusBounty sortedArrayUsingSelector:@selector(oo_compareNumerically:)];
newStatusInvalid = NO;
if ([statusNames count] != [sortedStatusBounty count])
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'oolite_legal_status_bounty' and 'oolite_legal_status_names' array size in descriptions.plist not equal - reverting to original legal status system.");
}
if ([sortedStatusBounty oo_unsignedIntAtIndex:0] != 0)
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'oolite_legal_status_bounty' array in descriptions.plist does not start at 0 - reverting to original ratings system.");
}
if (!newStatusInvalid)
{
for (i = 0; i < [sortedStatusBounty count]; ++i)
{
if (legalStatus < [sortedStatusBounty oo_intAtIndex:i])
{
if([statusNames oo_stringAtIndex:i-1] != nil)
{
return [statusNames oo_stringAtIndex:i-1];
}
else
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'nil' value returned when trying to display legal status - reverting to original legal status system.");
break;
}
}
}
}
if (newStatusInvalid)
{
enum { kStatusCount = 3 };
const int statusThresholds[kStatusCount - 1] =
{
1,
51
};
statusNames = [NSArray arrayWithObjects:@"Clean",@"Offender",@"Fugitive",nil];
for (i = 0; i != kStatusCount - 1; ++i)
{
if (legalStatus < statusThresholds[i]) return [statusNames oo_stringAtIndex:i];
}
return [statusNames oo_stringAtIndex:kStatusCount - 1];
}
return [statusNames oo_stringAtIndex:[sortedStatusBounty count] - 1];
}
EDIT: So...things still left to fix:
- Minus values need to make code revert to hardcoded ratings and legal status system.
- Need to be able to sort string arrays (
oolite_rating_names
andoolite_legal_status_names
) to match order of integer arrays (oolite_rating_kills
andoolite_legal_status_bounty
)
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
Laptop PC: CPU: Intel i5-10300H Quad Core 4.5GHz (Turbo-Charged) GPU: Nvidia GeForce GTX 1650 RAM: 32GB DDR4
Re: Source Code and Ideas question
The easiest approach is probably to create a temporary NSMutableDictionary within the function with the numeric value as the key and the string as the value. Then, sort the integer array, proceed as before, and get the appropriate string for the integer value from the dictionaryPleb wrote:[*]Need to be able to sort string arrays (oolite_rating_names
andoolite_legal_status_names
) to match order of integer arrays (oolite_rating_kills
andoolite_legal_status_bounty
)
For your current code, what happens if you put:
Code: Select all
(
0,
8,
16,
32,
64,
126,
512,
2560,
6400
);
Code: Select all
(
0,
"8",
16,
32,
"64",
126,
512,
"2560",
6400
);
- JensAyton
- Grand Admiral Emeritus
- Posts: 6657
- Joined: Sat Apr 02, 2005 2:43 pm
- Location: Sweden
- Contact:
Re: Source Code and Ideas question
’Fraid not; there are no NSNumbers in OpenStep format plists.cim wrote:(the lack of quotes is the key difference: those *are* now NSNumbers rather than NSStrings
E-mail: [email protected]
Re: Source Code and Ideas question
So if I'm following what you're saying correctly (I'm at work so I can't test this yet) the quotation marks wouldn't make a difference because it still reads the values as NSString and not NSNumbers? Thank you for the NSMutableDictionary idea cim, I will try this out later!JensAyton wrote:’Fraid not; there are no NSNumbers in OpenStep format plists.cim wrote:(the lack of quotes is the key difference: those *are* now NSNumbers rather than NSStrings
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
Laptop PC: CPU: Intel i5-10300H Quad Core 4.5GHz (Turbo-Charged) GPU: Nvidia GeForce GTX 1650 RAM: 32GB DDR4
Re: Source Code and Ideas question
Following this very intently...
Re: Source Code and Ideas question
Okay, that's going to make this harder to test.JensAyton wrote:’Fraid not; there are no NSNumbers in OpenStep format plists.cim wrote:(the lack of quotes is the key difference: those *are* now NSNumbers rather than NSStrings
Something like this as an OXP's
descriptions.plist
is still possible, though.
Code: Select all
<dict>
<key>oolite_legal_status_bounty</key>
<array>
<integer>0</integer>
<integer>1</integer>
<integer>51</integer> <!-- <string>51</string> is also a possibility to be really awkward -->
</array>
</dict>
Re: Source Code and Ideas question
Okay, making some real progress here now. I have made modifications to the code now that will ensure that if someone has a descriptions.plist file looking either like this: Or like this: Then it loads in the right order, and does not crash (as it would have done before without the new changes). Essentially I have put in safeguards that if the values in the array were actually NSNumbers and not NSStrings then it will convert the NSNumbers to NSStrings so that the code doesn't break. It should be noted that I've only put numbers at the start of the ratings and legal status text so I can tell if it's failed without having to look in the log (but there are obviously still log entries for when something does go wrong). So, only thing I haven't fixed here yet (based on tests provided) is negative values but it's getting late so this may have to wait until tomorrow. Also need to figure out a way to have the ☆ and ★ appear properly in the hardcoded bits, as at the moment they do not... But I wanted to share what I had so far!
Code: Select all
{
"oolite_rating_kills" =
(
"15",
"8",
0,
"32",
"64",
"6400",
"512",
"2560",
"128"
);
"oolite_rating_names" =
(
"3Poor",
"2Mostly Harmless",
"1Harmless",
"4Average",
"5Above Average",
"9★★★ E L I T E ★★★",
"7Dangerous",
"8☆ Deadly ☆",
"6Competent"
);
"oolite_legal_status_bounty" =
(
"1",
0,
"51"
);
"oolite_legal_status_names" =
(
"2Offender",
"1Clean",
"3Fugitive"
);
}
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>oolite_rating_kills</key>
<array>
<integer>16</integer>
<integer>8</integer>
<string>0</string>
<integer>32</integer>
<integer>64</integer>
<integer>6400</integer>
<integer>512</integer>
<integer>2560</integer>
<integer>128</integer>
</array>
<key>oolite_rating_names</key>
<array>
<string>3Poor</string>
<string>2Mostly Harmless</string>
<string>1Harmless</string>
<string>4Average</string>
<string>5Above Average</string>
<string>9★★★ E L I T E ★★★</string>
<string>7Dangerous</string>
<string>8☆ Deadly ☆</string>
<string>6Competent</string>
</array>
<key>oolite_legal_status_bounty</key>
<array>
<integer>1</integer>
<string>0</string>
<integer>51</integer>
</array>
<key>oolite_legal_status_names</key>
<array>
<string>2Offender</string>
<string>1Clean</string>
<string>3Fugitive</string>
</array>
</dict>
</plist>
Code: Select all
NSString *OODisplayRatingStringFromKillCount(unsigned kills)
{
NSArray *ratingNames = nil;
NSArray *ratingKills = nil;
NSMutableArray *mutableRatingKills = [[NSMutableArray alloc] init];
NSArray *sortedRatingKills = nil;
NSMutableDictionary *ratingNamesDict = [[NSMutableDictionary alloc] init];
NSString *killString;
NSString *ratingString;
unsigned i;
BOOL newRatingsInvalid;
ratingNames = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_rating_names"];
ratingKills = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_rating_kills"];
newRatingsInvalid = NO;
for (i = 0; i < [ratingKills count]; ++i)
{
ratingString = [NSString stringWithFormat:@"%u", [ratingKills oo_intAtIndex:i]];
[mutableRatingKills addObject:ratingString];
}
sortedRatingKills = [mutableRatingKills sortedArrayUsingSelector:@selector(oo_compareNumerically:)];
for (i = 0; i < [mutableRatingKills count]; ++i)
{
killString = [NSString stringWithFormat:@"%u", [mutableRatingKills oo_unsignedIntAtIndex:i]];
ratingString = [ratingNames oo_stringAtIndex:i];
[ratingNamesDict setObject:ratingString forKey:killString];
}
if ([ratingNames count] != [sortedRatingKills count])
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'oolite_rating_kills' and 'oolite_rating_names' array size in descriptions.plist not equal - reverting to original ratings system.");
}
if ([sortedRatingKills oo_unsignedIntAtIndex:0] != 0)
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'oolite_rating_kills' array in descriptions.plist does not start at 0 - reverting to original ratings system.");
}
if (!newRatingsInvalid)
{
for (i = 0; i < [sortedRatingKills count]; ++i)
{
if (kills < [sortedRatingKills oo_unsignedIntAtIndex:i])
{
killString = [NSString stringWithFormat:@"%u", [sortedRatingKills oo_unsignedIntAtIndex:i-1]];
if ([ratingNamesDict objectForKey:killString] != nil)
{
return [ratingNamesDict objectForKey:killString];
}
else
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'nil' value returned when trying to display rating status - reverting to original ratings system.");
break;
}
}
}
}
if (newRatingsInvalid)
{
enum { kRatingCount = 9 };
const unsigned killThresholds[kRatingCount - 1] =
{
0x0008,
0x0010,
0x0020,
0x0040,
0x0080,
0x0200,
0x0A00,
0x1900
};
ratingNames = [NSArray arrayWithObjects:@"Harmless",@"Mostly Harmless",@"Poor",@"Average",@"Above Average",@"Competent",@"Dangerous",@"☆ Deadly ☆",@"★★★ E L I T E ★★★",nil];
for (i = 0; i < kRatingCount - 1; ++i)
{
if (kills < killThresholds[i]) return [ratingNames oo_stringAtIndex:i];
}
return [ratingNames oo_stringAtIndex:kRatingCount - 1];
}
i = [sortedRatingKills count] - 1;
killString = [NSString stringWithFormat:@"%u", [sortedRatingKills oo_unsignedIntAtIndex:i]];
return [ratingNamesDict objectForKey:killString];
}
Code: Select all
NSString *OODisplayStringFromLegalStatus(int legalStatus)
{
NSArray *statusNames = nil;
NSArray *statusBounty = nil;
NSMutableArray *mutableStatusBounty = [[NSMutableArray alloc] init];
NSArray *sortedStatusBounty = nil;
NSMutableDictionary *statusNamesDict = [[NSMutableDictionary alloc] init];
NSString *bountyString;
NSString *statusString;
unsigned i;
BOOL newStatusInvalid;
statusNames = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_legal_status_names"];
statusBounty = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_legal_status_bounty"];
newStatusInvalid = NO;
for (i = 0; i < [statusBounty count]; ++i)
{
bountyString = [NSString stringWithFormat:@"%u", [statusBounty oo_intAtIndex:i]];
[mutableStatusBounty addObject:bountyString];
}
sortedStatusBounty = [mutableStatusBounty sortedArrayUsingSelector:@selector(oo_compareNumerically:)];
for (i = 0; i < [mutableStatusBounty count]; ++i)
{
bountyString = [NSString stringWithFormat:@"%u", [mutableStatusBounty oo_unsignedIntAtIndex:i]];
statusString = [statusNames oo_stringAtIndex:i];
[statusNamesDict setObject:statusString forKey:bountyString];
}
if ([statusNames count] != [sortedStatusBounty count])
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'oolite_legal_status_bounty' and 'oolite_legal_status_names' array size in descriptions.plist not equal - reverting to original legal status system.");
}
if ([sortedStatusBounty oo_unsignedIntAtIndex:0] != 0)
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'oolite_legal_status_bounty' array in descriptions.plist does not start at 0 - reverting to original ratings system.");
}
if (!newStatusInvalid)
{
for (i = 0; i < [sortedStatusBounty count]; ++i)
{
if (legalStatus < [sortedStatusBounty oo_intAtIndex:i])
{
bountyString = [NSString stringWithFormat:@"%u", [sortedStatusBounty oo_unsignedIntAtIndex:i-1]];
if ([statusNamesDict objectForKey:bountyString] != nil)
{
return [statusNamesDict objectForKey:bountyString];
}
else
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'nil' value returned when trying to display legal status - reverting to original legal status system.");
break;
}
}
}
}
if (newStatusInvalid)
{
enum { kStatusCount = 3 };
const int statusThresholds[kStatusCount - 1] =
{
1,
51
};
statusNames = [NSArray arrayWithObjects:@"Clean",@"Offender",@"Fugitive",nil];
for (i = 0; i != kStatusCount - 1; ++i)
{
if (legalStatus < statusThresholds[i]) return [statusNames oo_stringAtIndex:i];
}
return [statusNames oo_stringAtIndex:kStatusCount - 1];
}
i = [sortedStatusBounty count] - 1;
bountyString = [NSString stringWithFormat:@"%u", [sortedStatusBounty oo_unsignedIntAtIndex:i]];
return [statusNamesDict objectForKey:bountyString];
}
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
Laptop PC: CPU: Intel i5-10300H Quad Core 4.5GHz (Turbo-Charged) GPU: Nvidia GeForce GTX 1650 RAM: 32GB DDR4
Re: Source Code and Ideas question
Sorry for the double post, but I have fixed the negative value problem: This now detects if there is a negative value. I've tested this using both layouts of plist files used in post above and this works.
Now if I could only fix the ☆ and ★ in the hardcoded bit...
Code: Select all
NSString *OODisplayRatingStringFromKillCount(unsigned kills)
{
NSArray *ratingNames = nil;
NSArray *ratingKills = nil;
NSMutableArray *mutableRatingKills = [[NSMutableArray alloc] init];
NSArray *sortedRatingKills = nil;
NSMutableDictionary *ratingNamesDict = [[NSMutableDictionary alloc] init];
NSString *killString;
NSString *ratingString;
unsigned i;
int killInt;
BOOL newRatingsInvalid;
ratingNames = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_rating_names"];
ratingKills = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_rating_kills"];
newRatingsInvalid = NO;
killInt = 0;
for (i = 0; i < [ratingKills count]; ++i)
{
ratingString = [NSString stringWithFormat:@"%u", [ratingKills oo_intAtIndex:i]];
killInt = [ratingString integerValue];
if (killInt < 0)
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'oolite_rating_kills' array in descriptions.plist contains a negative value - reverting to original legal status system.");
break;
}
}
for (i = 0; i < [ratingKills count]; ++i)
{
ratingString = [NSString stringWithFormat:@"%u", [ratingKills oo_intAtIndex:i]];
[mutableRatingKills addObject:ratingString];
}
sortedRatingKills = [mutableRatingKills sortedArrayUsingSelector:@selector(oo_compareNumerically:)];
for (i = 0; i < [mutableRatingKills count]; ++i)
{
killString = [NSString stringWithFormat:@"%u", [mutableRatingKills oo_unsignedIntAtIndex:i]];
ratingString = [ratingNames oo_stringAtIndex:i];
[ratingNamesDict setObject:ratingString forKey:killString];
}
if ([ratingNames count] != [sortedRatingKills count] && !newRatingsInvalid)
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'oolite_rating_kills' and 'oolite_rating_names' array size in descriptions.plist not equal - reverting to original ratings system.");
}
if ([sortedRatingKills oo_unsignedIntAtIndex:0] != 0 && !newRatingsInvalid)
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'oolite_rating_kills' array in descriptions.plist does not start at 0 - reverting to original ratings system.");
}
if (!newRatingsInvalid)
{
for (i = 0; i < [sortedRatingKills count]; ++i)
{
if (kills < [sortedRatingKills oo_unsignedIntAtIndex:i])
{
killString = [NSString stringWithFormat:@"%u", [sortedRatingKills oo_unsignedIntAtIndex:i-1]];
if ([ratingNamesDict objectForKey:killString] != nil)
{
return [ratingNamesDict objectForKey:killString];
}
else
{
newRatingsInvalid = YES;
OOLog(@"new.ratings.error", @"'nil' value returned when trying to display rating status - reverting to original ratings system.");
break;
}
}
}
}
if (newRatingsInvalid)
{
enum { kRatingCount = 9 };
const unsigned killThresholds[kRatingCount - 1] =
{
0x0008,
0x0010,
0x0020,
0x0040,
0x0080,
0x0200,
0x0A00,
0x1900
};
ratingNames = [NSArray arrayWithObjects:@"Harmless",@"Mostly Harmless",@"Poor",@"Average",@"Above Average",@"Competent",@"Dangerous",@"☆ Deadly ☆",@"★★★ E L I T E ★★★",nil];
for (i = 0; i < kRatingCount - 1; ++i)
{
if (kills < killThresholds[i]) return [ratingNames oo_stringAtIndex:i];
}
return [ratingNames oo_stringAtIndex:kRatingCount - 1];
}
i = [sortedRatingKills count] - 1;
killString = [NSString stringWithFormat:@"%u", [sortedRatingKills oo_unsignedIntAtIndex:i]];
return [ratingNamesDict objectForKey:killString];
}
Code: Select all
NSString *OODisplayStringFromLegalStatus(int legalStatus)
{
NSArray *statusNames = nil;
NSArray *statusBounty = nil;
NSMutableArray *mutableStatusBounty = [[NSMutableArray alloc] init];
NSArray *sortedStatusBounty = nil;
NSMutableDictionary *statusNamesDict = [[NSMutableDictionary alloc] init];
NSString *bountyString;
NSString *statusString;
unsigned i;
int bountyInt;
BOOL newStatusInvalid;
statusNames = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_legal_status_names"];
statusBounty = [[UNIVERSE descriptions] oo_arrayForKey:@"oolite_legal_status_bounty"];
newStatusInvalid = NO;
bountyInt = 0;
for (i = 0; i < [statusBounty count]; ++i)
{
bountyString = [NSString stringWithFormat:@"%u", [statusBounty oo_intAtIndex:i]];
bountyInt = [bountyString integerValue];
if (bountyInt < 0)
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'oolite_legal_status_bounty' array in descriptions.plist contains a negative value - reverting to original legal status system.");
break;
}
}
for (i = 0; i < [statusBounty count]; ++i)
{
bountyString = [NSString stringWithFormat:@"%u", [statusBounty oo_intAtIndex:i]];
[mutableStatusBounty addObject:bountyString];
}
sortedStatusBounty = [mutableStatusBounty sortedArrayUsingSelector:@selector(oo_compareNumerically:)];
for (i = 0; i < [mutableStatusBounty count]; ++i)
{
bountyString = [NSString stringWithFormat:@"%u", [mutableStatusBounty oo_unsignedIntAtIndex:i]];
statusString = [statusNames oo_stringAtIndex:i];
[statusNamesDict setObject:statusString forKey:bountyString];
}
if ([statusNames count] != [sortedStatusBounty count] && !newStatusInvalid)
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'oolite_legal_status_bounty' and 'oolite_legal_status_names' array size in descriptions.plist not equal - reverting to original legal status system.");
}
if ([sortedStatusBounty oo_unsignedIntAtIndex:0] != 0 && !newStatusInvalid)
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'oolite_legal_status_bounty' array in descriptions.plist does not start at 0 - reverting to original ratings system.");
}
if (!newStatusInvalid)
{
for (i = 0; i < [sortedStatusBounty count]; ++i)
{
if (legalStatus < [sortedStatusBounty oo_intAtIndex:i])
{
bountyString = [NSString stringWithFormat:@"%u", [sortedStatusBounty oo_unsignedIntAtIndex:i-1]];
if ([statusNamesDict objectForKey:bountyString] != nil)
{
return [statusNamesDict objectForKey:bountyString];
}
else
{
newStatusInvalid = YES;
OOLog(@"new.legal.status.error", @"'nil' value returned when trying to display legal status - reverting to original legal status system.");
break;
}
}
}
}
if (newStatusInvalid)
{
enum { kStatusCount = 3 };
const int statusThresholds[kStatusCount - 1] =
{
1,
51
};
statusNames = [NSArray arrayWithObjects:@"Clean",@"Offender",@"Fugitive",nil];
for (i = 0; i != kStatusCount - 1; ++i)
{
if (legalStatus < statusThresholds[i]) return [statusNames oo_stringAtIndex:i];
}
return [statusNames oo_stringAtIndex:kStatusCount - 1];
}
i = [sortedStatusBounty count] - 1;
bountyString = [NSString stringWithFormat:@"%u", [sortedStatusBounty oo_unsignedIntAtIndex:i]];
return [statusNamesDict objectForKey:bountyString];
}
Now if I could only fix the ☆ and ★ in the hardcoded bit...
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
Laptop PC: CPU: Intel i5-10300H Quad Core 4.5GHz (Turbo-Charged) GPU: Nvidia GeForce GTX 1650 RAM: 32GB DDR4
Re: Source Code and Ideas question
Looking good. Another tip, then: you have two increasingly long functions which are essentially the same apart from:
- choice of variable names
- two string constants to do the initial extraction from descriptions.plist
- two array constants for the fallback
You should therefore be able to replace them with one long function and two short ones.
The stars aren't showing up because the translation from Unicode to Oolite's non-standard 256-character encoding only happens when processing text from plists. A literal string is just treated as is. So you'll need to embed the characters in Oolite's charset - octal notation is probably the shortest way: you can find the stars' byte numbers by looking at the oolite-font texture or plist.
- choice of variable names
- two string constants to do the initial extraction from descriptions.plist
- two array constants for the fallback
You should therefore be able to replace them with one long function and two short ones.
The stars aren't showing up because the translation from Unicode to Oolite's non-standard 256-character encoding only happens when processing text from plists. A literal string is just treated as is. So you'll need to embed the characters in Oolite's charset - octal notation is probably the shortest way: you can find the stars' byte numbers by looking at the oolite-font texture or plist.