This is HighScoreTable.m in view mode; [Download] [Up]
#import <stdio.h> // strcpy #import <stdlib.h> // malloc #import <strings.h> #import <objc/typedstream.h> // highscore tables #import <daymisckit/daymisckit.h> #import <gamekit/gamekit.h> #import <appkit/appkit.h> #import <remote/NXProxy.h> @implementation HighScoreTable - init // designated initializer sets up game variables { // to sensible values. [super init]; tag = 0; title = [[DAYString alloc] init]; emptySlot = [[HighScoreSlot alloc] init]; // ***** use proper class maxHighScores = MAXSCORES; return self; } - setEmptySlotClass:classObject { if (emptySlot) [emptySlot free]; emptySlot = [[classObject alloc] init]; return self; } - setStringValue:(const char *)aString { [title setStringValue:aString]; return self; } - (BOOL)samePlayer:slot1 :slot2 { // if the login names are same, assume same user. You can override this // to go by machine name or whatever. if (![slot1 userName] || ![slot2 userName]) return NO; if (strcmp([slot1 userName], [slot2 userName])) return NO; return YES; } - (int)numEntriesByPlayer:aSlot // return # of high scores player has { int i, count = 0; for (i=0; i<[self count]; i++) if ([self samePlayer:[self objectAt:i] :aSlot]) count++; return count; } - (int)lowestSlotByPlayer:aSlot // return lowest scoring slot by player { int i; // look for appropriate slot from end of list to front for (i=[self count]-1; i>=0; i--) if ([self samePlayer:[self objectAt:i] :aSlot]) return i; // return [self count] if didn't find a slot that matches criteria return [self count]; } - (const char *)stringValue { return [title stringValue]; } - (int)tag { return tag; } - setTag:(int)newTag { tag = newTag; return self; } - (int)maxHighScores { return maxHighScores; } - setMaxHighScores:(int)newMax { maxHighScores = newMax; return self; } - (int)maxScoresPerPlayer { return maxScoresPerPlayer; } - setMaxScoresPerPlayer:(int)newMax { maxScoresPerPlayer = newMax; return self; } - (BOOL)addSlot:newSlot // keeps the table sorted as slots are added. { int i; return [self addSlot:newSlot where:&i]; } - (BOOL)addSlot:newSlot where:(int *)w // keeps table sorted as slots added. { // the key for the sort is from slots' -isAbove method... int i; id xtraObj; for (i=0; i<[self count]; i++) { // find where to add slot if ([newSlot isAbove:[self objectAt:i]]) break; } // insert it [self insertObject:newSlot at:i]; // insert regardless if (maxScoresPerPlayer) { // 0 == unlimited entries if ([self numEntriesByPlayer:newSlot] > maxScoresPerPlayer) { // have one more entry by this player than allowed, so // we'll delete the lowest. int xtraSlotNum = [self lowestSlotByPlayer:newSlot]; #ifdef NOISYDEBUG fprintf(stderr, "HighScoreTable: removing extra entry by player %s.\n", [newSlot userName]); #endif // delete the actual slot and free it. xtraObj = [self removeObject:[self objectAt:xtraSlotNum]]; if ([xtraObj isProxy]) [xtraObj freeProxy]; else [xtraObj free]; // if this was the slot we just added, then return // that we didn't add it after all... if (i == xtraSlotNum) { *w = [self count]; return NO; } } } // prune the table so it doesn't grow too big. max # is set by init. // done by deleting slots from the end to the front until size is OK. while ([self count] > maxHighScores) { xtraObj = [self removeLastObject]; if ([xtraObj isProxy]) [xtraObj freeProxy]; else [xtraObj free]; } *w = i; // return by reference where we added it. if (i >= maxHighScores) return NO; return YES; } - objectAt:(unsigned)index { if (index >= [self count]) return emptySlot; return [super objectAt:index]; } - free { [emptySlot free]; return [super free]; } - copy { // build a new table with new slots (i.e. don't just copy id pointers, // actually make new objects) int i; id aCopy = [[[self class] alloc] init]; [aCopy setEmptySlotClass:[emptySlot class]]; [aCopy setMaxHighScores:maxHighScores]; for (i=0; i<[self count]; i++) { [aCopy addSlot:[[self objectAt:i] copy]]; } return aCopy; } - read:(NXTypedStream *)stream { // don't save emptySlot since it is easy enough to create [super read:stream]; NXReadTypes(stream, "iii", &maxHighScores, &maxScoresPerPlayer, &tag); emptySlot = NXReadObject(stream); title = NXReadObject(stream); return self; } - write:(NXTypedStream *)stream { [super write:stream]; NXWriteTypes(stream, "iii", &maxHighScores, &maxScoresPerPlayer, &tag); NXWriteObject(stream, emptySlot); // saved to preserve class type NXWriteObject(stream, title); return self; } // NXTransport protocol implementation: List must contain objects that // also use this protocol; otherwise it won't xfer by copy properly! - encodeUsing:(id <NXEncoding>)portal { int i, n = [self count]; [portal encodeData:&n ofType:"i"]; [portal encodeData:&maxHighScores ofType:"i"]; [portal encodeData:&maxScoresPerPlayer ofType:"i"]; [portal encodeData:&tag ofType:"i"]; for (i=0; i<n; i++) { [portal encodeObjectBycopy:[self objectAt:i]]; } [portal encodeObjectBycopy:emptySlot]; [portal encodeObjectBycopy:title]; return self; } - decodeUsing:(id <NXDecoding>)portal { int i, n; [portal decodeData:&n ofType:"i"]; [portal decodeData:&maxHighScores ofType:"i"]; [portal decodeData:&maxScoresPerPlayer ofType:"i"]; [portal decodeData:&tag ofType:"i"]; [self freeObjects]; // make sure that we're empty for (i=0; i<n; i++) { [self addObject:[portal decodeObject]]; } emptySlot = [portal decodeObject]; title = [portal decodeObject]; return self; } - encodeRemotelyFor:(NXConnection *)connection freeAfterEncoding:(BOOL *)flagp isBycopy:(BOOL)isByCopy { if (isByCopy) return self; //encode object (copy it) // super will encode the proxy otherwise return [super encodeRemotelyFor:connection freeAfterEncoding:flagp isBycopy:isByCopy]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.