home *** CD-ROM | disk | FTP | other *** search
-
- #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
-