This is Thinker.m in view mode; [Download] [Up]
#import "Thinker.h"
#import "BackView.h"
#import "DisplayManager.h"
#import "CacheManager.h"
#import "ActorMgr.h"
#import "SoundMgr.h"
#import "Xoxeroids.h"
#import "psfuncts.h"
#import "EKProgressView.h"
#import <drivers/event_status_driver.h>
@implementation Thinker
unsigned timeInMS, lastTimeInMS, obscureTime;
float timeScale;
float maxTimeScale;
float collisionDistance;
id actorMgr, displayMgr, cacheMgr, soundMgr;
id scenario;
id mainView;
id abackView;
id gcontentView;
id gameList;
int gameIndex;
id sceneOneStepper;
BOOL pauseState;
BOOL fullScreen;
BOOL keepLooping;
BOOL obscureMouse;
NXEventHandle eventhandle;
double oldKeyThreshold;
int BULLET1SND,
BULLET2SND,
EXP1SND,
EXP2SND,
EXP3SND,
SHIPSND,
WARPSND,
FUTILITYSND;
static unsigned currentTimeInMs()
{
struct timeval curTime;
gettimeofday (&curTime, NULL);
return (curTime.tv_sec) * 1000 + curTime.tv_usec / 1000;
}
NXZone *scenarioZone, *bundleZone;
- init
{
[super init];
imageNames = [[List alloc] init];
imageRequestor = [[List alloc] init];
soundsToCache = [[Storage allocFromZone:[self zone]]
initCount:8
elementSize: sizeof(int)
description: @encode(int)];
return self;
}
- appDidInit:sender
{
NXZone *actorZone, *displayZone;
id commonBundle;
char path[1024];
srandom(time(0));
timeInMS = lastTimeInMS = currentTimeInMs();
eventhandle = NXOpenEventStatus();
oldKeyThreshold = NXKeyRepeatThreshold(eventhandle);
NXSetKeyRepeatThreshold(eventhandle, 300.0);
[self createTimer];
mainView = abackView = backView;
gameWindow = littleWindow;
gcontentView = [littleWindow contentView];
[nullInfoBox getFrame: &inspectorFrame];
actorZone = NXCreateZone(vm_page_size, vm_page_size, YES);
displayZone = NXCreateZone(vm_page_size, vm_page_size, YES);
scenarioZone = NXCreateZone(vm_page_size, vm_page_size, YES);
bundleZone = NXCreateZone(vm_page_size, vm_page_size, YES);
actorMgr = [[ActorMgr allocFromZone:actorZone] init];
displayMgr = [[DisplayManager allocFromZone:displayZone] init];
cacheMgr = [[CacheManager allocFromZone:displayZone] init];
[self getSoundSetting];
[self setupGameBrowser];
[[NXBundle mainBundle] getPath:path forResource:"CommonEffects" ofType:"XoXo"];
commonBundle = [[NXBundle allocFromZone:bundleZone] initForDirectory:path];
[[[commonBundle classNamed:"CommonStuff"] allocFromZone:scenarioZone] init];
[self selectGame:nil];
[[invisibleInfoBox window] makeKeyAndOrderFront:self];
[littleWindow makeFirstResponder:mainView];
[littleWindow setBackgroundGray:NX_BLACK];
[littleWindow makeKeyAndOrderFront:self];
[self newGame:self];
return self;
}
void timedEntryFunction (DPSTimedEntry timedEntry, double timeNow, void *theObject)
{ [(id)theObject doOneStepLoop];
}
- createTimer
{
if (!timerValid)
{
timerValid = YES;
timer = DPSAddTimedEntry(0.02, &timedEntryFunction, self, NX_BASETHRESHOLD);
}
return self;
}
- removeTimer
{
if (timerValid) DPSRemoveTimedEntry (timer);
timerValid = NO;
return self;
}
- doOneStepLoop
{
NXEvent dummyEvent, *pEvent;
[mainView lockFocus];
keepLooping = YES;
do {
[self oneStep];
while ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent
waitFor:0 threshold:NX_BASETHRESHOLD])
{
if ((dummyEvent.type & (NX_KEYDOWNMASK|NX_KEYUPMASK)) &&
(!(dummyEvent.flags & NX_COMMANDMASK)))
{
// if it's a key event other than a command key, we save
// ourselves the overhead of a focus change
pEvent = [NXApp getNextEvent: NX_ALLEVENTS
waitFor:0 threshold:NX_BASETHRESHOLD];
[NXApp sendEvent: pEvent];
}
else
{
keepLooping = NO;
break;
}
}
} while (timerValid && keepLooping);
[mainView unlockFocus];
return self;
}
- justOneStep
{
[mainView lockFocus];
// [self oneStep];
{ // new behavior to replace onestep above
[actorMgr makeActorsPerform:@selector(erase)];
[cacheMgr oneStep];
[displayMgr oneStep];
}
[mainView unlockFocus];
return self;
}
- oneStep
{
float tinterval;
lastTimeInMS = timeInMS;
timeInMS = currentTimeInMs();
tinterval = timeInMS - lastTimeInMS;
if (obscureMouse && (timeInMS > obscureTime))
{
PSobscurecursor();
obscureTime = timeInMS + 5000;
}
if (tinterval < 1) tinterval = 1;
timeScale = tinterval/100;
if (timeScale > maxTimeScale) timeScale = maxTimeScale;
[soundMgr oneStep];
[sceneOneStepper oneStep]; // notify the scenario, if it cares
[actorMgr oneStep];
[cacheMgr oneStep];
[displayMgr oneStep];
NXPing (); // Synchronize postscript for smoother animation
return self;
}
// This should return a float between 0 and 1
float frandom()
{
float val = (random() & 0x7fffffff);
val /= 0x7fffffff;
return val;
}
float randBetween(float a, float b)
{
float val, scale, t;
if (a > b)
{ t = a; a = b; b = t;
}
scale = (b-a);
val = scale * frandom();
return (a + val);
}
- toggleFullScreen:sender;
{
[self setFullScreen: !fullScreen];
return self;
}
- setFullScreen:(BOOL)flag
{
if (flag)
{
NXRect r={{0, 0}};
if ([self bigWindowOK])
{
[NXApp getScreenSize:&(r.size)];
[self createBigWindowIfNecessary];
tweakWindow([bigWindow windowNum], 40);
[self installGameViewsIntoWindow:bigWindow];
[bigWindow placeWindow:&r];
[bigWindow makeKeyAndOrderFront:self];
[bigWindow display];
}
else flag = NO;
}
else
{
[bigWindow orderOut:self];
[self installGameViewsIntoWindow:littleWindow];
[littleWindow makeKeyAndOrderFront:self];
[littleWindow display];
}
fullScreen = flag;
return self;
}
- toggleUserPause:sender
{
[self setPauseState: (pauseState ^ 1)];
return self;
}
- setPauseState:(BOOL)flag
{
if (flag) [self removeTimer];
else [self createTimer];
pauseState = flag;
return self;
}
- appDidHide:sender
{
[self setPauseState:(pauseState | 2)];
return self;
}
- appDidUnhide:sender
{
[self setPauseState:(pauseState & ~2)];
return self;
}
- appDidBecomeActive:sender
{
[self setPauseState:(pauseState & ~4)];
NXSetKeyRepeatThreshold(eventhandle, 300.0);
return self;
}
- appDidResignActive:sender
{
[self setPauseState:(pauseState | 4)];
NXSetKeyRepeatThreshold(eventhandle, oldKeyThreshold);
return self;
}
- windowDidBecomeKey:sender
{
if (sender == littleWindow || sender == bigWindow)
[self setPauseState:(pauseState & ~8)];
return self;
}
- windowDidResignKey:sender
{
if (sender == littleWindow || sender == bigWindow)
[self setPauseState:(pauseState | 8)];
return self;
}
- windowDidMove:sender
{
if ((sender == littleWindow) && ([scenario respondsTo:@selector(windowDidMove:)]))
[scenario windowDidMove:sender];
return self;
}
- appWillTerminate:sender
{
NXSetKeyRepeatThreshold(eventhandle, oldKeyThreshold);
return self;
}
- newGame:sender
{
[self setPauseState:(pauseState & ~1)];
[actorMgr setGameStatus:GAME_RUNNING];
[actorMgr requestLevel:0];
return self;
}
// Image Loading status stuff was borrowed from Erik Kay,
// slightly munged for xox by sam
// add an image filename to the image resource list
- addImageResource:(const char *)r for:whom
{
//! we cheat here a bit and take advantage of the fact that a list just
//! takes id's which are pointers, and therefore, character pointers work
//! just fine too. Probably not the best thing to do...
[imageNames addObject:(id)NXCopyStringBuffer(r)];
[imageRequestor addObject:whom];
return self;
}
- addSoundResource:(int)sound
{
[soundsToCache addElement:&sound];
return self;
}
// preload resources for the app
- loadResources
{
int i, count, progress = 0;
char *str;
id whom;
int soundndx;
// actually load the images
count = [imageNames count];
for (i = 0; i < count; i++)
{
str = (char *)[imageNames objectAt:i];
whom = [imageRequestor objectAt:i];
[[statusText setStringValue:str] display];
[whom cacheImage:str];
free(str);
// update the progress bar
progress++;
[progressView setProgress:progress];
NXPing();
}
// convert/cache the sounds
count = [soundsToCache count];
for (i = 0; i < count; i++)
{
soundndx = *(int *)[soundsToCache elementAt:i];
str = (char *)[soundMgr soundName:soundndx];
if (str)
{
[[statusText setStringValue:str] display];
[soundMgr cacheSound:soundndx];
}
// update the progress bar
progress++;
[progressView setProgress:progress];
NXPing();
}
[imageNames empty];
[imageRequestor empty];
[soundsToCache empty];
return self;
}
@end
@implementation List (XoxAdditions)
- performInOrder:(SEL)aSelector
{
int i, count = numElements;
for (i=0; i<count; i++)
[dataPtr[i] perform: aSelector];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.