mirror of
https://github.com/gamache/blehm.git
synced 2025-02-16 22:30:33 +00:00
1907 lines
73 KiB
ObjectPascal
Executable File
1907 lines
73 KiB
ObjectPascal
Executable File
Program ZeroGravity;{Copyright © 1986 by Duane Blehm, All Rights Reserved}
|
|
|
|
{ Version 1.0 code enhancement,shrink pict resources...cover,mask,cntlbox}
|
|
{Format note: 'tabs' for this text should be set to '3'}
|
|
|
|
USES MacIntf; {used for TML version 2.0,instead of the 'includes' directive}
|
|
|
|
{$T APPL ZGRV set the TYPE and CREATOR}
|
|
{$B+ set the application's bundle bit }
|
|
{$L ZeroGravity.rsrc} { Link resource file }
|
|
|
|
CONST
|
|
WindResId = 128; {Window Resource}
|
|
|
|
lastMenu = 5; {Number of Menus}
|
|
appleMenu = 1;
|
|
fileMenu = 256; {Menu Resource Id's}
|
|
optionMenu = 257;
|
|
worksMenu = 258;
|
|
messageMenu = 259;
|
|
|
|
{Control Resources}
|
|
pressResume = 130;
|
|
pressEnd = 131;
|
|
|
|
Disable = 255; {disable button controls,i-322}
|
|
Enable = 0;
|
|
maxint = 32767;
|
|
Pi = 3.141593;
|
|
Decimal = '.';
|
|
|
|
TYPE
|
|
PilotActs = (InChamber,OpenDoors,FreeFlight,EnterLock,Resting);
|
|
SoundList = (AirDoor,BigDoor,Game,GravTone,Buzz,Blue,Silence);
|
|
|
|
PictureList = (Pilot,BigPilot,Pod,Door,Star,Flip,BigFlip,Numeral,
|
|
BigChamber,TimerBox,TargetBox,AirLock,ScoreBox,Mask,Title,
|
|
CntlBox,Cover);
|
|
{2/14/87 note: Cntlbox... will use QuickDraw Commands
|
|
also will shrink Mask in resource and expand it later..all to save
|
|
on size of resources and application size!}
|
|
|
|
DialogList = (Help,About,Name,LScore,SCode,BMap);
|
|
|
|
{We used MacroMind's 'Music to Video' utility to convert Blue Danube notes
|
|
into a resource... then did some compacting,etc. to come up with our 'SONG'
|
|
resource which contains notes for use with the FourTone synthesizer}
|
|
|
|
SongRec = Record {we'll import a song record from our 'SONG' resource file}
|
|
noteCount:integer;{how many notes in this song}
|
|
pitch:array[1..160,1..4] of Longint;{160 notes,4 voices}
|
|
duration:array[1..160] of integer;{how many ticks will pitch play}
|
|
end;
|
|
|
|
SongPtr = ^SongRec;
|
|
SongHandle = ^SongPtr;
|
|
|
|
Force = Record {will contain facts about force acting on Pilot in Chamber}
|
|
magH,magV: integer; {horizontal,vertical magnitude of force}
|
|
duration: integer; {how many loops will force be in effect}
|
|
liteNdx:integer; {index to array of rects used to draw lites}
|
|
end;{of record}
|
|
|
|
ScoreNText = Record {we're keeping our scores in a resource}
|
|
nameStr:Str255;
|
|
score: Real;
|
|
end;
|
|
|
|
ScoreBlk = Array[1..3,1..3] of ScoreNText;{3 difficultys,3 names per diff.}
|
|
|
|
ScorePtr = ^ScoreBlk;
|
|
|
|
|
|
VAR
|
|
tDialPeek: DialogPeek; {so we can access TextH field of dialogrec}
|
|
FontFacts: FontInfo; {so we can change TEHandle size stuff}
|
|
MouseLoc,tpoint: Point;
|
|
FigureLoScore: boolean; {if true-track loscores; if false-don't bother}
|
|
ScoreControl: array[2..3] of Handle;{radio buttons,LoScoreDialog}
|
|
ScoreHandle: Handle; {handle to our LoScore resource data}
|
|
NameHandle: Handle; {Handle to textitem in NameDialog box}
|
|
NameString: Str255; {will hold LoScore name from one time to next}
|
|
WindFrame: array[1..16] of Rect;{array frame rects around window}
|
|
PauseUnderWay: Boolean; {flag if pause}
|
|
LastPilot: Rect; {last location of Pilot}
|
|
OffPatch, {Pilot sized rect. over OffChamber shape}
|
|
OffPilotMask: Rect; {Pilot sized rect. over OffMask shape}
|
|
DoorOpening: Boolean; {true while airlock door is opening}
|
|
FlipInProgress: Boolean; {true if a flip is being animated}
|
|
OffHold: Rect; {Pilot sized rect. in OffScreen bitmap}
|
|
CntlCover: Rect; {used to draw gray over diff. Controls}
|
|
LoopCount: integer; {count each loop of game for avgscore}
|
|
WholePart,
|
|
FractPart: Longint; {used to draw real numbers}
|
|
RotateRight: Boolean; {will pilot flip rotate right or left?}
|
|
|
|
tinyBonus,tinyPenalty,
|
|
tinyScore,
|
|
tinyLoScore: Rect;{four boxes for drawing text into box}
|
|
BonusRect,PenaltyRect,
|
|
ScoreRect,
|
|
LoScoreRect: Rect; {four boxes inside of scoreBox}
|
|
TimeLine: integer; {how many loops to increment per game}
|
|
TimeSlide: Rect; {rect inside TimerBox for drawing indictor}
|
|
Difficulty: integer; {1 issoeasy,2 issoso,3 issotuff}
|
|
Radio: Array[1..3] of ControlHandle;{difficulty buttons}
|
|
PicNdx: PictureList;{use as index to picture arrays}
|
|
R: Array[Pilot..Cover] of Rect;{all our pic/shape rectangles!}
|
|
Home: Point;{base for drawing shapes, R[BigChamber].topleft}
|
|
TargetNum: Rect;{destination for Numerals in TargetBox}
|
|
|
|
ChamberRgn: RgnHandle;{mask drawing of chamber interior}
|
|
|
|
TopCover,BotCover:Rect; {two halfs of the chamber cover that opens}
|
|
PilotStatus: PilotActs;{will determine which animation is going}
|
|
CoverLoops: integer;
|
|
|
|
{all our offscreen rectangles}
|
|
OffPod: Array[1..2] of Rect;
|
|
OffDoor,OffFrame,
|
|
OffStar,InStar,OffStarWindow,
|
|
OffBigChamber,
|
|
OffTargetBox,OffMask,
|
|
OffTimerBox,OffScoreBox,
|
|
OffAirLock,OffTitle: Rect;
|
|
OffNumeral: Array[0..3] of Rect;
|
|
OffFlip: Array[1..7] of Rect;
|
|
OffBigFlip: Array[1..7] Of Rect;
|
|
OffDoorSlide: Rect;
|
|
OffPilot: array[1..3,1..3] of Rect;
|
|
OffBigPilot: array[1..3,1..3] of Rect;
|
|
|
|
StarRgn,BigChamberRgn,{most regions are used to 'mask' during CopyBits}
|
|
LimitRgn,
|
|
DoorRgn,DoorSlideRgn,
|
|
CoverRgn,tRgn: RgnHandle;
|
|
StarBox: Rect;
|
|
|
|
TargetRgn: Array[0..3] of RgnHandle;{Rgns for finding subscore}
|
|
Bonus,
|
|
Penalty: Longint;{running total of all subscores for game}
|
|
SubScore: Longint;{score for distance of pilot from scorecenter}
|
|
LoScore: ScorePtr;{access ScoreBlk in Resource file}
|
|
AvgScore: Real;{Score for game divided by no. of loops}
|
|
ScoreCenter: Point;
|
|
ScoreStr,tStr: Str255;
|
|
ScoreH,ScoreV: integer;{location of pen prior to drawing Score string}
|
|
|
|
MouseRect, {limit mouse movement to this rect}
|
|
DeltaRect: Rect; {map rect for copter control;dh,dv}
|
|
BorderRect: Rect;
|
|
|
|
PilotNdx: Point; {index for OffPilot array}
|
|
Dh,Dv: Integer; {Offset for Pilot rectangle/shape}
|
|
Grav: array[1..30] of Force; {will wind varibles for game}
|
|
GravNdx: integer;{index for Grav array}
|
|
Gh,Gv: Integer;{offset for gravity forces}
|
|
Sustain: integer;{how many loops will force work?}
|
|
Nh,Nv: integer;{net effect of Dh,Dv and Gh,Gv}
|
|
Lights: array[0..16] of Rect;{list of lights around chamber}
|
|
LightNdx: integer;
|
|
|
|
myMenus: Array[1..lastMenu] of MenuHandle;
|
|
refNum,theMenu,
|
|
theItem: integer;
|
|
SoundOn: Boolean; {flag for sound off or on, a menu option}
|
|
Finished: Boolean; {terminate the program,quit}
|
|
GameUnderWay: Boolean; {are we playing or pausing?}
|
|
ClockCursor: CursHandle; {handle to watch cursor}
|
|
myWindow: WindowPtr; {our game window}
|
|
wRecord: WindowRecord;{allocate record on stack}
|
|
DialNdx: DialogList;{will step through our dialogs array}
|
|
myDialog: Array[Help..BMap] of DialogPtr;
|
|
myDialogRec: Array[Help..BMap] of DialogRecord;
|
|
Screen,DragArea: Rect;
|
|
mySize: Size; {longint for CompactMem call}
|
|
|
|
OffScreen,OldBits,
|
|
InScreen: BitMap; {for drawing into offscreen}
|
|
SizeOfOff: Size; {Size offscreen bitmap}
|
|
OffRowBytes: Integer;
|
|
|
|
pPict: Array[Pilot..CntlBox] of PicHandle;{array of pictures}
|
|
|
|
ResumeButton,
|
|
EndButton: ControlHandle; { handles to controlbuttons }
|
|
|
|
aTick: Longint; {TickCount varible, sound delay}
|
|
|
|
{Sound varibles}
|
|
Buff: Array[AirDoor..Buzz] of Longint;{for Sound buffers}
|
|
myPtr: Ptr;
|
|
myHandle: Handle;
|
|
Sound: Array[AirDoor..Blue] of FFSynthPtr;{FreeForm synthesizer sound}
|
|
BlueSynth: FTSynthPtr; {Blue is a FourTone sound}
|
|
BlueSound: FTSndRecPtr; {four FourTone Sounds}
|
|
SoundParmBlk: ParmBlkPtr; {used for PBWrite instead of StartSound}
|
|
WhichSound: SoundList; {which sound is being played?}
|
|
err: OSerr;
|
|
SawToothWave: wavePtr;
|
|
SquareWave: wavePtr;
|
|
ToneTicks,ToneDelay:Longint;
|
|
mySong: SongHandle;
|
|
mySongPtr: SongPtr;
|
|
NoteCount: Longint;
|
|
|
|
{**********************************************}
|
|
procedure MoveRect(VAR aRect:Rect;h,v:integer;WhichCorner:integer);
|
|
{move aRect so that 'whichCorner' is alligned with the point h,v}
|
|
Begin
|
|
Case WhichCorner of
|
|
1:Begin{aRect.topleft to h,v}
|
|
aRect.right := aRect.right - aRect.left + h;
|
|
aRect.bottom := aRect.bottom - aRect.top + v;
|
|
aRect.left := h;
|
|
aRect.top := v;
|
|
end;
|
|
2:Begin{aRect.topright to h,v}
|
|
aRect.left := h - aRect.right + aRect.left;{h - width}
|
|
aRect.bottom := aRect.bottom - aRect.top + v;
|
|
aRect.right := h;
|
|
aRect.top := v;
|
|
end;
|
|
3:Begin{aRect.bottomright to h,v}
|
|
aRect.left := h - aRect.right + aRect.left;{h - width}
|
|
aRect.top := v - aRect.bottom + aRect.top;{h - width}
|
|
aRect.right := h;
|
|
aRect.bottom := v;
|
|
end;
|
|
4:Begin{aRect.bottomleft to h,v}
|
|
aRect.right := aRect.right - aRect.left + h;
|
|
aRect.top := v - aRect.bottom + aRect.top;{h - width}
|
|
aRect.left := h;
|
|
aRect.bottom := v;
|
|
end;
|
|
end;{of case whichmatch}
|
|
End;
|
|
|
|
procedure DrawLoScores;{into loScoredialog window}
|
|
var
|
|
i,j:integer;
|
|
begin
|
|
{draw LoScores into Dialog window}
|
|
For i := 1 to 3 do begin
|
|
For j := 1 to 3 do begin
|
|
MoveTo((i-1)*160 + 10,j*16 + 60);
|
|
DrawString(LoScore^[i,j].nameStr);
|
|
|
|
WholePart := trunc(LoScore^[i,j].score);{whole part of real number}
|
|
NumToString(WholePart,ScoreStr);
|
|
FractPart := Round((LoScore^[i,j].score-WholePart)*1000);
|
|
NumToString(FractPart,tStr);
|
|
While length(tStr) < 3 do tStr := concat('0',tStr);{ if fractpart< 0.1}
|
|
ScoreStr := concat(ScoreStr,Decimal,tStr);
|
|
MoveTo(i*160-10-StringWidth(ScoreStr),j*16+60);
|
|
DrawString(ScoreStr);
|
|
end; {for j}
|
|
end;{for i}
|
|
end;{procedure}
|
|
|
|
procedure DrawIntegerIntoBox(theInteger:integer;theRect:Rect);
|
|
Begin
|
|
NumToString(theInteger,ScoreStr);{rom call.. convert integer into string}
|
|
MoveTo(theRect.right-StringWidth(ScoreStr),theRect.bottom);
|
|
EraseRect(theRect);
|
|
DrawString(ScoreStr);
|
|
end;
|
|
|
|
procedure DrawScoreIntoBox(theScore:Real;theRect:Rect);
|
|
Begin
|
|
WholePart := trunc(theScore); {Whole&Fract Parts are Global Longint}
|
|
NumToString(WholePart,ScoreStr);
|
|
FractPart := Round((theScore-WholePart)*1000);
|
|
NumToString(FractPart,tStr);
|
|
While length(tStr) < 3 do tStr := concat('0',tStr);{ if fractpart< 0.1}
|
|
ScoreStr := concat(ScoreStr,Decimal,tStr);
|
|
MoveTo(theRect.right-StringWidth(ScoreStr),theRect.bottom);
|
|
EraseRect(theRect);
|
|
DrawString(ScoreStr);
|
|
End;{of procedure}
|
|
|
|
procedure ProcessNewLoScore;{display new LoScore stuff and get name}
|
|
var
|
|
itemHit,i,index: integer;
|
|
Begin
|
|
{put up the dialog box... get nameStr}
|
|
Case Difficulty of
|
|
1:ParamText('IsSoEasy','','','');{we're using the ^1 character, in Resource}
|
|
2:ParamText('IsSoSo','','','');
|
|
3:ParamText('IsSoTuff','','','');{display difficulty string in DialogBox}
|
|
end;{of Case}
|
|
|
|
ShowWindow(myDialog[Name]);{show the hidden dialog window}
|
|
SelectWindow(myDialog[Name]);
|
|
SetIText(NameHandle,NameString);{put default in text box}
|
|
SelIText(myDialog[Name],4,0,maxint);{select the text}
|
|
|
|
Repeat
|
|
ModalDialog(Nil,itemHit);{Modal does an Update event for the dialog box}
|
|
|
|
Until(itemHit = 1);{ok button}
|
|
|
|
GetIText(NameHandle,NameString);{must be happy with text..so use it}
|
|
{Test the length of the text... shorten if its too long}
|
|
i := length(NameString);
|
|
While (StringWidth(NameString)> 86) do begin {limit width of string}
|
|
Dec(i);
|
|
NameString := copy(NameString,1,i);{drop one char off the string}
|
|
end;
|
|
|
|
HideWindow(myDialog[Name]);{close the dialogwindow}
|
|
SelectWindow(myWindow);
|
|
|
|
{sort the New LoScore}
|
|
index := 3;{we know that score is less than 3 already}
|
|
For i := 2 Downto 1 do
|
|
If AvgScore < LoScore^[Difficulty,i].score then index := i;
|
|
|
|
i := 3;
|
|
While (i > index) do begin {switch old for new scores}
|
|
LoScore^[Difficulty,i] := LoScore^[Difficulty,i - 1];
|
|
dec(i);
|
|
end;{While}
|
|
LoScore^[Difficulty,index].score := AvgScore;
|
|
LoScore^[Difficulty,index].nameStr := NameString;
|
|
|
|
DrawScoreIntoBox(LoScore^[Difficulty,1].score,tinyLoScore);{lowest to scorebox}
|
|
|
|
ChangedResource(ScoreHandle);{flag so we will write out changes on Quit}
|
|
End;{of procedure}
|
|
|
|
procedure CreateLoScoreStuff;
|
|
{load in our LoScores from resource file}
|
|
Begin
|
|
ScoreHandle := GetResource('LSCR',128);{we're keeping LoScores in Resource}
|
|
HLock(ScoreHandle);{lock it permanently.. for speed}
|
|
LoScore := ScorePtr(ScoreHandle^);
|
|
end;
|
|
|
|
procedure WriteASoundBlock(aSoundPtr:Ptr;BuffSize:Longint;LastTick:Longint);
|
|
{make changes to our SoundParmBlk and then start the sound,the lasttick pause
|
|
is included due to occassional buzz/click/or worse if sound is written
|
|
immediately.. might be because Sound Driver set ioResult to zero before
|
|
the other soundstuff was complete.. and we happened to peek at it at just
|
|
the wrong moment}
|
|
Begin
|
|
SoundParmBlk^.iobuffer := aSoundPtr;{set pointer to our sound}
|
|
SoundParmBlk^.ioreqcount := BuffSize;{size of our sound buffer}
|
|
Repeat Until(TickCount > LastTick);{we'll wait a tick before writing sound}
|
|
err := PBWrite(SoundParmBlk,true);{start the sound, asynch}
|
|
end;
|
|
|
|
procedure InitialFourToneSound;
|
|
{Set NoteCount to first pitch and duration of our Song array (loaded from
|
|
resource file), load that data into BlueSound record and start the sound.
|
|
The varible ToneDelay is checked on each event loop, will flag if another note
|
|
needs to be loaded into BlueSound. We're loading in TakeCareSound...,if
|
|
BlueSound duration runs out then the Song is restarted from the top.}
|
|
var
|
|
i:integer;
|
|
Begin
|
|
NoteCount := 1;
|
|
|
|
BlueSound^.sound1Rate := mySongPtr^.pitch[NoteCount,1];
|
|
BlueSound^.sound2Rate := mySongPtr^.pitch[NoteCount,2];
|
|
BlueSound^.sound3Rate := mySongPtr^.pitch[NoteCount,3];
|
|
BlueSound^.sound4Rate := mySongPtr^.pitch[NoteCount,4];
|
|
BlueSound^.duration := 80;{none of our notes is over 60 ticks long}
|
|
|
|
ToneDelay := mySongPtr^.duration[NoteCount] + TickCount;
|
|
|
|
If SoundOn then
|
|
WriteASoundBlock(ptr(Sound[Blue]),SizeOf(Sound[Blue]^),TickCount);
|
|
End;{of Procedure}
|
|
|
|
|
|
procedure CreateSound;
|
|
Var
|
|
i,j,k: integer;
|
|
Begin
|
|
{load Blue Danube from resource file}
|
|
mySong := SongHandle(GetResource('SONG',524));{this is BlueDanube notes}
|
|
HLock(Handle(mySong));{we're locking it permanently}
|
|
mySongPtr := SongPtr(mySong^);
|
|
|
|
new(SawToothWave); {wavePtr...a SawToothWave form for Blue sound}
|
|
new(SquareWave); {wavePtr...a squarewave form for Blue sound}
|
|
for i := 0 to 127 do {build our four tone waves}
|
|
begin
|
|
SawToothWave^[i] := 2*i;{sort of a raspy sound....}
|
|
SawToothWave^[i+128] := 0;
|
|
SquareWave^[i] := 0;
|
|
SquareWave^[i+128] := 192;{height of Square determines Loudness}
|
|
end;
|
|
|
|
{we'll coerce Blue to FreeForm pointer throughout the program just so we
|
|
can use WhichSound and our SoundList type later on....}
|
|
new(BlueSynth); {my FTSynthPtr, FourTone Synthesizer}
|
|
BlueSynth^.mode := ftMode;
|
|
|
|
{note: the duration field must be reset after each Bluesound as the driver
|
|
decrements its value}
|
|
|
|
new(BlueSound);{our fourtone sound}
|
|
BlueSound^.sound1Phase := 0;
|
|
BlueSound^.sound2Phase := 128;
|
|
BlueSound^.sound3Phase := 128; {out of phase just for fun}
|
|
BlueSound^.sound4Phase := 0;
|
|
BlueSound^.sound1Wave := SawToothWave;
|
|
BlueSound^.sound2Wave := SawToothWave;
|
|
BlueSound^.sound3Wave := SquareWave;
|
|
BlueSound^.sound4Wave := SquareWave;
|
|
|
|
{must make sndRec point to our Sound}
|
|
BlueSynth^.sndRec := BlueSound;
|
|
Sound[Blue] := FFSynthPtr(BlueSynth);{its just a pointer.. so coerce it}
|
|
|
|
Buff[AirDoor] := 1486;{size all the freeform buffers}
|
|
Buff[BigDoor] := 3706;{size should be multiple of 370 plus 6 bytes}
|
|
Buff[Game] := 3706; {6 bytes for mode and count fields}
|
|
Buff[GravTone] := 1486;
|
|
Buff[Buzz] := 1486;
|
|
|
|
{now create all the FreeForm sounds....}
|
|
For WhichSound := AirDoor to Buzz do begin {they all have these in common}
|
|
myHandle := NewHandle(Buff[WhichSound]);{new block for our sound}
|
|
HLock(myHandle); {we're locking the blocks permanently!!}
|
|
myPtr := myHandle^; {dereference the handle}
|
|
Sound[WhichSound] := FFSynthPtr(myPtr);
|
|
Sound[WhichSound]^.mode := ffMode;
|
|
{knock off 6 bytes for mode & count.. plus 1 for switch to Zero base}
|
|
Buff[WhichSound] := Buff[WhichSound] - 7;
|
|
end;
|
|
|
|
{AirDoor Stuff}
|
|
Sound[AirDoor]^.count := FixRatio(1,6);{see the Sound Driver stuff}
|
|
j := 0;
|
|
While j<= Buff[AirDoor] do Begin
|
|
Sound[AirDoor]^.WaveBytes[j] := abs(Random) div 1024; {fill up the buffer}
|
|
inc(j);
|
|
end; { of while}
|
|
|
|
{BigDoor sound}
|
|
Sound[BigDoor]^.count := FixRatio(1,2);
|
|
j := 0;
|
|
While j<= Buff[BigDoor] do Begin
|
|
If j< 2000 then i := abs(Random) div 1024; {random number 0 to 64}
|
|
If j = 2000 then i := 127;
|
|
if (j mod 127 = 0) and (i=127) then i := 0
|
|
else if (j mod 127 = 0) and (i=0) then i := 127;
|
|
Sound[BigDoor]^.WaveBytes[j] := i; {fill up the buffer}
|
|
inc(j);
|
|
end; { of while}
|
|
|
|
{Game background sound}
|
|
Sound[Game]^.count := FixRatio(1,8); {fixed point notation}
|
|
j := 0;
|
|
k := 1;
|
|
While j<= Buff[Game] do Begin
|
|
If k > 0 then i := (abs(Random) div 1024) + 127;
|
|
If k > 10 then i := 96;
|
|
If k > 20 then i := 159;
|
|
If k > 30 then k := 0;
|
|
Sound[Game]^.WaveBytes[j] := i; {fill up the buffer}
|
|
inc(k);
|
|
inc(j);
|
|
end; { of while}
|
|
|
|
{GravTone when Force Changes sound...}
|
|
{We'll set the Count Field each time we play a tone..in AnimateOneLoop}
|
|
j := 0;
|
|
i := 0;
|
|
k := 0;
|
|
While j<= Buff[GravTone] do Begin {Square wave with freq of 128 bytes}
|
|
Sound[GravTone]^.WaveBytes[j] := i;
|
|
If k = 64 then i := 255;
|
|
If k = 128 then begin
|
|
k := 0;
|
|
i := 0;
|
|
end;{if k}
|
|
inc(k);
|
|
inc(j);
|
|
end; { of while}
|
|
|
|
{Buzz Sound during penaltys against the chamber wall}
|
|
Sound[Buzz]^.count := FixRatio(1,2); {fixed point notation}
|
|
j := 0;
|
|
i := 0;
|
|
While j<= Buff[Buzz] do Begin
|
|
Sound[Buzz]^.WaveBytes[j] := i;
|
|
If i < 255 then inc(i) else i := 0;{SawTooth wave}
|
|
inc(j);
|
|
end; { of while}
|
|
|
|
{create our Sound Parameter block for use with PBWrite}
|
|
new(SoundParmBlk);
|
|
with SoundParmBlk^ do begin {see Apple tech note 19, PBWrite vs. StartSound}
|
|
iocompletion := nil;
|
|
iorefnum := -4;
|
|
{we'll poke in the pointers and size stuff in WriteASoundBlock}
|
|
ioresult := 0; {will Start sound ,MainEventLoop}
|
|
end; {of with}
|
|
end;
|
|
|
|
procedure BuildGravArray(Diff:integer);{Diff is difficulty}
|
|
{build array of 30 forces to be used during game}
|
|
var
|
|
mag,dir: real;
|
|
maxmag,maxdir,maxtime,mintime:real;
|
|
i:integer;
|
|
Begin
|
|
maxmag := diff + 1.5; {maximum magnitude of vector}
|
|
maxdir := diff*Pi/3.0; {maximum change in angle of vector}
|
|
maxtime := 30.0/diff; {maximum number of loops force will last}
|
|
minTime := 15.0/diff; {minimum loops force will last}
|
|
dir := abs(Random/(maxint/2*Pi));{set a random angle to start}
|
|
For i := 1 to 30 do begin
|
|
mag := abs(Random/(maxint/maxmag));{magnitude of force vector}
|
|
If mag < 1.0 then mag := 1.0;
|
|
dir := abs(dir + Random/(maxint/maxdir));{angle of force in radians}
|
|
If dir > 2*Pi then dir := dir - 2*Pi;
|
|
Grav[i].magH := round(mag*cos(dir));{x axis component of force}
|
|
Grav[i].magV := round(mag*sin(dir));{y axis component of force}
|
|
Grav[i].duration := round(abs(Random/(maxint/(maxtime-mintime)))+mintime);
|
|
Grav[i].liteNdx := round(dir/(2*Pi/16.0));{which lite to light?}
|
|
end;{for i := }
|
|
End;
|
|
|
|
procedure CreateWindow;{windows,dialogs}
|
|
var
|
|
tRect: Rect;
|
|
Begin
|
|
myWindow := GetNewWindow(WindResId,@wRecord,Pointer(-1));
|
|
SetRect(tRect,0,0,600,400);{this will clip OffScreen bitMaps as well!!}
|
|
|
|
{remember: Dialog itemlists should be purgable, dialogs invisible}
|
|
SetDAFont(202);{Stuttgart font for all the dialogs...}
|
|
For DialNdx := Help to BMap do begin {read all the dialogs into array}
|
|
myDialog[DialNdx] :=
|
|
GetNewDialog(ord(DialNdx)+129,@myDialogRec[DialNdx],myWindow);
|
|
SetPort(myDialog[DialNdx]);
|
|
ClipRect(tRect);{set clip to smaller size..}
|
|
TextSize(9); {size of font}
|
|
end;
|
|
|
|
{editText item TextHandle controls the font stuff in the NameDialog box}
|
|
GetFontInfo(FontFacts);{will get fontstuff from current grafport(BMap)}
|
|
SetPort(myDialog[Name]);{has a editable text item...effects Text}
|
|
tDialPeek := DialogPeek(myDialog[Name]);{coerce pointer}
|
|
tDialPeek^.textH^^.txSize := 9;{see TextHandle stuff,changing font size}
|
|
tDialPeek^.textH^^.fontAscent := FontFacts.ascent;
|
|
tDialPeek^.textH^^.lineHeight := FontFacts.ascent + FontFacts.descent;
|
|
|
|
ShowWindow(myWindow);{done so back to myWindow...}
|
|
SetPort(myWindow);
|
|
ClipRect(tRect); {i-166, set cliprgn to small rgn}
|
|
TextFont(202);{Stuttgart font,installed in resource file}
|
|
TextSize(9);
|
|
end;
|
|
|
|
procedure CreateControls;
|
|
var
|
|
i,width: integer;
|
|
Begin
|
|
ResumeButton := GetNewControl(pressResume,myWindow);
|
|
EndButton := GetNewControl(pressEnd,myWindow);
|
|
{load Difficulty buttons,locate them later in CntlBox rectangle}
|
|
For i := 1 to 3 do Radio[i] := GetNewControl(132 + i,myWindow);
|
|
End;
|
|
|
|
procedure CreatePictures; {get all the PICT's from resource file}
|
|
{we've created a type called PictureList so that we can access the
|
|
PicHandle and Rect arrays by 'title' instead of a number,also
|
|
all Picture.picframes are preset in resource to proper coordinates for
|
|
drawing into OffScreen bitmap otherwise they'd have to be 'Located' first.}
|
|
var
|
|
tRect:Rect;
|
|
Begin
|
|
For PicNdx := Pilot to Title do begin {almost all of PictureList..}
|
|
pPict[PicNdx] := GetPicture(ord(PicNdx) + 128);{get picture}
|
|
R[PicNdx] := pPict[PicNdx]^^.picFrame;{get Rect for picture}
|
|
end;
|
|
|
|
{create CntlBox picture... just a frame}
|
|
SetRect(R[CntlBox],0,0,97,59);{size of CntlBox}
|
|
tRect := R[CntlBox];
|
|
InSetRect(tRect,2,2);
|
|
pPict[CntlBox] := OpenPicture(R[CntlBox]);
|
|
EraseRect(R[CntlBox]);
|
|
FrameRect(R[CntlBox]);
|
|
FrameRoundRect(R[CntlBox],20,20);
|
|
FrameRect(tRect);
|
|
ClosePicture;
|
|
end;
|
|
|
|
procedure CreateOffScreenBitMap; {see CopyBits stuff,also tech.note 41}
|
|
var
|
|
bRect: Rect;
|
|
Begin
|
|
{OffScreen BitMap stuff, will hold all our shapes for animation}
|
|
SetRect(bRect,0,0,320,296); { drawing area,size to contain all pics }
|
|
with bRect do begin
|
|
OffRowBytes := (((right - left -1) div 16) +1) * 2;{has to be even!}
|
|
SizeOfOff := (bottom - top) * OffRowBytes;
|
|
OffSetRect(bRect,-left,-top);{move rect to 0,0 topleft}
|
|
end; { of with }
|
|
|
|
OffScreen.baseAddr := QDPtr(NewPtr(SizeOfOff));
|
|
OffScreen.rowbytes := OffRowBytes;
|
|
OffScreen.bounds := bRect;
|
|
|
|
{InScreen BitMap, Shapes are 'overlaid' in InScreen, then go to myWindow}
|
|
bRect := myWindow^.portRect;{ drawing area same as our onscreen window! }
|
|
with bRect do begin
|
|
OffRowBytes := (((right - left -1) div 16) +1) * 2;{has to be even!}
|
|
SizeOfOff := (bottom - top) * OffRowBytes;
|
|
OffSetRect(bRect,-left,-top);
|
|
end; { of with }
|
|
|
|
InScreen.baseAddr := QDPtr(NewPtr(SizeOfOff));
|
|
InScreen.rowbytes := OffRowBytes;
|
|
InScreen.bounds := bRect;
|
|
End;
|
|
|
|
procedure DrawPicsIntoOffScreen;
|
|
{watch out for clipping of portRect,visRgn,& clipRgn of grafport record}
|
|
var
|
|
tRect:Rect;
|
|
Begin
|
|
OldBits := myWindow^.portBits; {preserve old BitMap}
|
|
tRect := myWindow^.portRect;
|
|
SetPortBits(OffScreen); { our new BitMap }
|
|
PortSize(400,330);{adjust portRect,visRgn & clipRgn for larger draw area}
|
|
CopyRgn(myWindow^.visRgn,tRgn);
|
|
CopyRgn(myWindow^.clipRgn,myWindow^.visRgn);
|
|
|
|
FillRect(OffScreen.bounds,white); {erase our new BitMap to white}
|
|
|
|
{All our Pictures were copied from a drawing of the bitmap in FullPaint
|
|
(the bitmap was located UpperLeft on the page) into the
|
|
ScrapBook. Then transfered from the ScrapBook to PICT resources with
|
|
ResEdit. By doing this the Picture.picFrame is already set to
|
|
Coordinates of picture location in OffScreen. OtherWise all Rects
|
|
would have to be moved into correct position before drawing.}
|
|
|
|
For PicNdx := Pilot to Title do begin
|
|
DrawPicture(pPict[PicNdx],R[PicNdx]); {draw all the pictures}
|
|
ReleaseResource(handle(pPict[PicNdx])); {done so dump them}
|
|
end;
|
|
|
|
{we've dumped the pictures so how about compacting the heap before loading
|
|
other stuff, like all those sound buffers we're going to lock down?}
|
|
mySize := CompactMem(1024);{force compaction of the heap...???}
|
|
|
|
myWindow^.portRect := tRect; {restore old portRect}
|
|
CopyRgn(tRgn,myWindow^.visRgn);{restore old visRgn}
|
|
SetPortBits(OldBits); {restore old bitmap}
|
|
end;
|
|
|
|
procedure CreateOffScreenRects;
|
|
{ where are all those shapes? locate all the shapes in the OffScreen bitmap
|
|
by defining the rectangles that contain them. We'll use the OffScreen rects
|
|
as the 'Source' in Copybits. Probably would be more efficent to have all
|
|
OffScreen Rects in a list like our pict Rects and have them predefined in
|
|
a resource file... then just load in the whole bunch all at once. }
|
|
var
|
|
i,j: integer;
|
|
tRect: Rect;
|
|
Begin
|
|
OffBigChamber := R[BigChamber];
|
|
|
|
tRect := R[Pilot]; {locate OffPilot shapes}
|
|
tRect.right := tRect.left + 19;
|
|
tRect.bottom := tRect.top + 19; {size of one pilot}
|
|
For i := 1 to 3 do begin
|
|
For j := 1 to 3 do begin
|
|
OffPilot[j,i] := tRect;{load 9 shapes}
|
|
tRect.left := tRect.left + 19;
|
|
tRect.right := tRect.right + 19;
|
|
end;{for j}
|
|
MoveRect(tRect,R[Pilot].left,tRect.bottom,1);{next row}
|
|
end;{for i}
|
|
R[Pilot] := tRect;{resize Pilot to a single shape}
|
|
|
|
tRect := R[BigPilot]; {locate OffBigPilot shapes}
|
|
tRect.right := tRect.left + 22;
|
|
tRect.bottom := tRect.top + 22; {size of one BigPilot}
|
|
For i := 1 to 3 do begin
|
|
For j := 1 to 3 do begin
|
|
OffBigPilot[j,i] := tRect;{9 shapes}
|
|
tRect.left := tRect.left + 22;
|
|
tRect.right := tRect.right + 22;
|
|
end;{for j}
|
|
MoveRect(tRect,R[BigChamber].right,tRect.bottom,1);
|
|
end;{for i}
|
|
R[BigPilot] := tRect;{resize to hold one BigPilot}
|
|
|
|
tRect := R[Pod];
|
|
tRect.right := tRect.left + 27;
|
|
OffPod[1] := tRect;{empty pod}
|
|
OffSetRect(tRect,26,0);{2 Pods one with pilot,one empty}
|
|
OffPod[2] := tRect;
|
|
R[Pod] := tRect;
|
|
|
|
OffDoor := R[Door];
|
|
OffDoor.right := OffDoor.left + 65;
|
|
OffFrame := R[Door];
|
|
OffFrame.left := OffFrame.right - 33;
|
|
R[Door] := OffFrame;
|
|
OffDoorSlide := OffFrame;{DoorSlide will slide along OffDoor}
|
|
OffSetRect(OffDoorSlide,OffDoor.right-OffDoorSlide.right,0);
|
|
|
|
OffStar := R[Star];
|
|
SetRect(tRect,0,0,38,38);
|
|
OffStarWindow := tRect;
|
|
MoveRect(OffStarWindow,OffStar.right,OffStar.top,2);
|
|
InStar := OffStarWindow;
|
|
|
|
tRect := R[BigFlip];
|
|
tRect.right := tRect.left + 22;{width of one flip}
|
|
For i := 1 to 7 do begin
|
|
OffBigFlip[i] := tRect;
|
|
tRect.left := tRect.left + 22;
|
|
tRect.right := tRect.right + 22;
|
|
end;{for i}
|
|
OffHold := tRect;{will hold last inscreen during freeflight animation}
|
|
MoveRect(OffHold,OffPod[2].right,R[TargetBox].bottom,1);
|
|
|
|
tRect := R[Flip];
|
|
tRect.right := tRect.left + 19;{width of one flip}
|
|
For i := 1 to 7 do begin
|
|
OffFlip[i] := tRect;
|
|
tRect.left := tRect.left + 19;
|
|
tRect.right := tRect.right + 19;
|
|
end;{for i}
|
|
OffPatch := tRect;{will be used to refresh background under pilot}
|
|
OffPilotMask := tRect;{will be used to mask target over pilot}
|
|
|
|
OffAirLock := R[AirLock];
|
|
OffTargetBox := R[TargetBox];
|
|
|
|
OffScoreBox := R[ScoreBox];
|
|
OffTimerBox := R[TimerBox];
|
|
OffTitle := R[Title];
|
|
|
|
tRect := R[Numeral];
|
|
tRect.right := tRect.left + 20;
|
|
for i := 0 to 3 do begin
|
|
OffNumeral[i] := tRect;
|
|
tRect.left := tRect.left + 20;
|
|
tRect.right := tRect.right + 20;
|
|
end;{for i}
|
|
TargetNum := tRect;
|
|
|
|
{expand Mask to size of BigChamber for OffPilotMask}
|
|
i := R[Mask].left - R[BigChamber].left;
|
|
InsetRect(R[Mask],-i,-i);
|
|
OffMask := R[Mask];
|
|
End;
|
|
|
|
procedure CreateRegions;
|
|
var i: integer;
|
|
Begin
|
|
StarRgn := NewRgn;{rgn used to mask stars drawn into InScreen}
|
|
LimitRgn := NewRgn;{rgn used to limit Pilot movement to inside chamber}
|
|
DoorRgn := NewRgn;
|
|
CoverRgn := NewRgn;{rgn used to mask Cover doors over chamber}
|
|
tRgn := NewRgn;{temporary region}
|
|
ChamberRgn := NewRgn;{rgn used to mask to chamber}
|
|
BigChamberRgn := NewRgn;{a little larger than chamber}
|
|
DoorSlideRgn := NewRgn;
|
|
for i := 0 to 3 do TargetRgn[i] := NewRgn;{used to find points/score}
|
|
End;
|
|
|
|
procedure DisplayDialog(WhichDialog:DialogList);
|
|
var
|
|
tRect,fRect: Rect;
|
|
itemHit,i,j: integer;
|
|
tPort: GrafPtr;
|
|
Begin
|
|
GetPort(tPort);
|
|
ShowWindow(myDialog[WhichDialog]);
|
|
SelectWindow(myDialog[WhichDialog]);
|
|
SetPort(myDialog[WhichDialog]); {so we can draw into our dialog window}
|
|
|
|
Case WhichDialog of
|
|
Help:
|
|
ModalDialog(Nil,itemHit); {close it no matter what was hit}
|
|
About:
|
|
ModalDialog(Nil,itemHit); {close it no matter what was hit}
|
|
LScore:begin
|
|
DrawLoScores;{draw the scorestuff into the dialog box}
|
|
|
|
Repeat
|
|
ModalDialog(Nil,itemHit); {find which button hit,OK or BACKFLIP}
|
|
|
|
Case itemHit of
|
|
2:begin{control button, start processing loScores}
|
|
SetCtlValue(ControlHandle(ScoreControl[2]),1);{set control true}
|
|
SetCtlValue(ControlHandle(ScoreControl[3]),0);{set control true}
|
|
FigureLoScore := True;{set the flag to true}
|
|
end;
|
|
3:begin{Stop processing LoScores}
|
|
SetCtlValue(ControlHandle(ScoreControl[2]),0);{set control true}
|
|
SetCtlValue(ControlHandle(ScoreControl[3]),1);{set control true}
|
|
FigureLoScore := False;{set the flag to true}
|
|
end;
|
|
6:begin{Reset the LoScores to defaults}
|
|
For i := 1 to 3 do
|
|
For j := 1 to 3 do begin
|
|
LoScore^[i,j].nameStr := 'Pilot';{set all nameStrings to pilot}
|
|
LoScore^[i,j].score := i + 1.0;{new loscores}
|
|
end;
|
|
InvalRect(myDialog[LScore]^.portRect);{modalDialog will redraw items}
|
|
EraseRect(myDialog[LScore]^.portRect);
|
|
DrawLoScores;{draw our reset scores back in}
|
|
DrawScoreIntoBox(LoScore^[Difficulty,1].score,tinyLoScore);
|
|
ChangedResource(ScoreHandle);{flag so we write out changes}
|
|
end;{case 6}
|
|
end; { of case itemHit}
|
|
|
|
Until (itemHit = 1); {the ok button or 'enter' key}
|
|
end;{LScore}
|
|
SCode:{about the sourcecode}
|
|
ModalDialog(Nil,itemHit); {close it no matter what was hit}
|
|
BMap:begin{peek offscreen bitmap}
|
|
CopyBits(OffScreen,myDialog[BMap]^.portBits,OffScreen.bounds,
|
|
OffScreen.bounds,srcCopy,nil); {copy bitmap to dialog box}
|
|
ModalDialog(Nil,itemHit); {close it no matter what was hit}
|
|
end;{BMap}
|
|
end;{Case WhichDialog}
|
|
|
|
HideWindow(myDialog[WhichDialog]);
|
|
SelectWindow(myWindow);{restore our game window}
|
|
SetPort(tPort);{restore port}
|
|
end;
|
|
|
|
procedure DoMenuCommand(mResult:LongInt);
|
|
var
|
|
name: Str255;
|
|
tPort: GrafPtr;
|
|
i,h: integer;
|
|
Begin
|
|
theMenu := HiWord(mResult);
|
|
theItem := LoWord(mResult);
|
|
Case theMenu of
|
|
appleMenu:
|
|
Begin
|
|
GetPort(tPort);
|
|
If theItem = 1 then DisplayDialog(About)
|
|
Else begin
|
|
GetItem(myMenus[1],theItem,name);{must be a desk acc.}
|
|
refNum := OpenDeskAcc(name);
|
|
end;
|
|
SetPort(tPort);
|
|
End;
|
|
fileMenu: Finished := True; {quit this program}
|
|
optionMenu:
|
|
Case theItem of
|
|
1:DisplayDialog(Help);
|
|
2:DisplayDialog(LScore);
|
|
3:Begin {toggle sound on or off}
|
|
If SoundOn then SoundOn := false else SoundOn := true;
|
|
CheckItem(myMenus[3],theItem,SoundOn);{check if true,none if false}
|
|
end;
|
|
end; { case theItem}
|
|
worksMenu:
|
|
Case theItem of
|
|
1:DisplayDialog(BMap);
|
|
2:DisplayDialog(SCode);
|
|
end;{case theItem}
|
|
End;
|
|
HiliteMenu(0);
|
|
End;
|
|
|
|
procedure InitialThisGame;{set up for opening the coverdoors/starting game}
|
|
var i:integer;
|
|
Begin
|
|
MoveRect(R[Pilot],Home.h+65,Home.v+65,1);{locate pilot}
|
|
MoveRect(OffPilotMask,OffMask.left+65,OffMask.top+65,1);{synch with pilot}
|
|
Dh := 0;Dv := 0;{no pilot movement}
|
|
BuildGravArray(Difficulty);{create the forces for this difficulty}
|
|
GravNdx := 1;{force stuff}
|
|
Sustain := 0;
|
|
LightNdx := 0;
|
|
CoverLoops := 24; {number of loops that coverdoor animation will take}
|
|
PilotStatus := OpenDoors; {this will begin coverdoor animation in maineventloop}
|
|
SetPt(PilotNdx,2,2);{this is standing still shape}
|
|
Penalty := 0;
|
|
Bonus := 0;{score stuff}
|
|
TimeLine := TimeSlide.left - 1;{TimeLine will be coordinate and counter}
|
|
LoopCount := 1;{divided into score to find avg.score}
|
|
FlipInProgress := False;
|
|
err := PBKillIO(SoundParmBlk,false);{kill AirLock sound}
|
|
WhichSound := BigDoor; {will start BigDoor Sound}
|
|
end;
|
|
|
|
procedure CloseTheCoverDoors;
|
|
Begin
|
|
TopCover.bottom := R[Cover].top + 69;
|
|
BotCover.top := R[Cover].bottom - 70;
|
|
End;{of CloseTheCover..}
|
|
|
|
procedure TakeCareControls(whichControl:ControlHandle;localMouse:point);
|
|
var
|
|
ControlHit,i: integer;
|
|
Begin
|
|
ControlHit := TrackControl(whichControl,localMouse,nil); { Find out which}
|
|
If ControlHit > 0 then {i-417}
|
|
Begin
|
|
If whichControl = ResumeButton then {RESUME the game..}
|
|
Begin
|
|
InsertMenu(myMenus[5],0); {display exit message}
|
|
For i := 1 to 4 do DisableItem(myMenus[i],0);
|
|
DrawMenuBar;
|
|
HideControl(ResumeButton);
|
|
HideControl(EndButton);
|
|
GameUnderWay := True; {we're back into game mode}
|
|
PauseUnderWay := False;
|
|
HideCursor;
|
|
FlushEvents(mDownMask,0); {clear all mouseDowns}
|
|
End;
|
|
If whichControl = EndButton then {END current game...}
|
|
Begin
|
|
HideControl(ResumeButton);{hide the resume and end}
|
|
HideControl(EndButton);
|
|
InvalRect(myWindow^.portRect);{force redraw of all}
|
|
CloseTheCoverDoors;
|
|
{close the airlock doors just in case}
|
|
OffSetRect(OffDoorSlide,OffDoor.right-OffDoorSlide.right,0);
|
|
For i := 1 to 3 do HiliteControl(Radio[i],0);{enable controls}
|
|
EraseRect(CntlCover);
|
|
For i := 1 to 3 do ShowControl(Radio[i]);
|
|
PilotStatus := Resting;{just so drawupdate will handle controls ok}
|
|
PauseUnderWay := False;
|
|
WhichSound := Silence;{no sounds}
|
|
End;
|
|
For i := 1 to 3 do begin
|
|
If whichControl = Radio[i] then begin
|
|
SetCtlValue(Radio[Difficulty],0); {uncheck current button}
|
|
Difficulty := i; {this is our new difficulty from 1 to 3}
|
|
{check new button,(contrlMax field must be set to 1)}
|
|
SetCtlValue(Radio[i],1);
|
|
DrawScoreIntoBox(LoScore^[Difficulty,1].score,tinyLoScore);
|
|
end;{if which}
|
|
end;{for i}
|
|
End; {of If ControlHit}
|
|
End; { of procedure}
|
|
|
|
procedure PauseThisGame; {called if a keydown during game}
|
|
var
|
|
i: integer;
|
|
Begin
|
|
err := PBKillIO(SoundParmBlk,false);{kill sound}
|
|
{copy current screen to InScreen, so update events are redrawn correctly}
|
|
CopyBits(myWindow^.portBits,InScreen,myWindow^.portRect,
|
|
InScreen.bounds,srcCopy,nil);
|
|
GameUnderWay := False; { halt animation }
|
|
ShowCursor;
|
|
ShowControl(ResumeButton);
|
|
ShowControl(EndButton);
|
|
DeleteMenu(MessageMenu); {remove exit message,i-354}
|
|
For i := 1 to 4 do EnableItem(myMenus[i],0);{show other menu options}
|
|
DrawMenuBar;
|
|
PauseUnderWay := True;
|
|
End;
|
|
|
|
procedure InitialAirLock;{setup to start Airlock animation}
|
|
Begin
|
|
CopyBits(OffScreen,myWindow^.portBits,OffHold,
|
|
R[BigPilot],srcCopy,nil);{erase last pilot}
|
|
MoveRect(R[BigPilot],R[Door].left+3,R[Door].top+3,1);{pilot in front of door}
|
|
SetPt(PilotNdx,2,2);{this is standing still shape}
|
|
Dh := 0;Dv := 0;
|
|
PilotStatus := EnterLock;{will begin Airlock animation}
|
|
FlipInProgress := False;
|
|
OffSetRect(OffDoorSlide,OffDoor.right-OffDoorSlide.right,0);{DoorSlide to right}
|
|
DoorOpening := True;{flag if door is opening or closing};
|
|
err := PBKillIO(SoundParmBlk,false);{kill Blue Danube sound}
|
|
WhichSound := AirDoor;{will start AirDoor Sound}
|
|
end;{procedure}
|
|
|
|
procedure InitialFreeFlight;{on mousedown in Pod... begin Freeflight}
|
|
var
|
|
i:integer;
|
|
Begin
|
|
GameUnderWay := True;
|
|
InsertMenu(myMenus[5],0);
|
|
For i := 1 to 4 do DisableItem(myMenus[i],0);
|
|
DrawMenuBar; {display exit message}
|
|
For i := 1 to 3 do HiliteControl(Radio[i],255);{disable Controls}
|
|
FillRect(BonusRect,Gray);
|
|
FillRect(PenaltyRect,Gray);{gray out for nice dark background}
|
|
FillRect(ScoreRect,Gray);
|
|
FillRect(LoScoreRect,Gray);
|
|
FillRect(TargetNum,Gray);
|
|
|
|
For i := 1 to 3 do HideControl(Radio[i]);{will generate update event}
|
|
BeginUpdate(myWindow);{clear Update stuff...}
|
|
EndUpDate(myWindow);
|
|
FlushEvents(updateMask,0);{clear Update stuff caused by HideControl}
|
|
|
|
FillRect(CntlCover,Gray);{cover where the controls were}
|
|
CopyBits(OffScreen,myWindow^.portBits,OffPod[1],
|
|
R[Pod],srcCopy,nil);{empty Pod}
|
|
{copy myWindow to InScreen so we can do animation 'overlays' in InScreen}
|
|
CopyBits(myWindow^.portBits,InScreen,myWindow^.portRect,
|
|
myWindow^.portRect,srcCopy,nil); {copy screen to inscreen}
|
|
|
|
MoveRect(R[BigPilot],R[Pod].left,R[Pod].bottom,4);{pilot on top of empty Pod}
|
|
{OffHold will hold a copy of background under the pilot}
|
|
CopyBits(InScreen,OffScreen,R[BigPilot],OffHold,srcCopy,nil);
|
|
SetPt(PilotNdx,2,2);{this is standing still shape}
|
|
PilotStatus := FreeFlight;{type of animation}
|
|
Dh := 0;Dv := 0;
|
|
FlipInProgress := False;
|
|
LoopCount := 1;{for flashing door}
|
|
HideCursor; {game mode,no normal mouse functions}
|
|
FlushEvents(mDownMask,0); {clear mousedowns}
|
|
|
|
WhichSound := Blue;{Blue Danube song}
|
|
InitialFourToneSound;{start the song}
|
|
end;
|
|
|
|
procedure BeginAFlip;
|
|
Begin {start a flip}
|
|
FlipInProgress := True;
|
|
If Dh>1 then begin {man is moving right so rotate flip right}
|
|
PilotNdx.h := 1;{set to first flip}
|
|
RotateRight := True;{will cause PilotNdx to be incremented}
|
|
end {if Dh>1}
|
|
else begin {else pilot will flip to the left}
|
|
PilotNdx.h := 7;
|
|
RotateRight := False;{will cause PilotNdx to be decremented}
|
|
end;{else}
|
|
end;{procedure}
|
|
|
|
procedure TakeCareMouseDown(myEvent:EventRecord);
|
|
var
|
|
Location: integer;
|
|
WhichWindow: WindowPtr;
|
|
WhichControl: ControlHandle;
|
|
MouseLoc: Point;
|
|
WindowLoc: integer;
|
|
ControlHit: integer;
|
|
Begin
|
|
If GameUnderWay = True then {handle a game click}
|
|
Case PilotStatus of
|
|
InChamber,OpenDoors: BeginAFlip;
|
|
|
|
FreeFlight:If RectInRgn(R[BigPilot],DoorRgn) then InitialAirLock
|
|
else BeginAFlip;
|
|
end {Case pilotStatus}
|
|
Else begin {Mouse is normal...handle normal functions}
|
|
MouseLoc := myEvent.Where; {Global coordinates}
|
|
WindowLoc := FindWindow(MouseLoc,WhichWindow); {I-287}
|
|
case WindowLoc of
|
|
inMenuBar:
|
|
DoMenuCommand(MenuSelect(MouseLoc));
|
|
inSysWindow:
|
|
SystemClick(myEvent,WhichWindow); {i-441}
|
|
inContent:
|
|
If WhichWindow <> FrontWindow then SelectWindow(WhichWindow)
|
|
else
|
|
Begin
|
|
GlobaltoLocal(MouseLoc);
|
|
ControlHit := FindControl(MouseLoc,whichWindow,whichControl);
|
|
If ControlHit > 0 then TakeCareControls(whichControl,Mouseloc)
|
|
Else {check for click in Pod Rect, will begin freeflight}
|
|
If (PtInRect(MouseLoc,R[Pod])) and (not(PauseUnderWay))
|
|
then InitialFreeFlight;
|
|
end;
|
|
end; {case of}
|
|
end; { of Else}
|
|
end; { TakeCareMouseDown }
|
|
|
|
PROCEDURE TakeCareKeyDown(Event:EventRecord);
|
|
Var
|
|
CharCode: char;
|
|
Begin
|
|
CharCode := chr(LoWord(BitAnd(Event.message,CharCodeMask)));
|
|
|
|
If BitAnd(Event.modifiers,CmdKey) = CmdKey then
|
|
DoMenuCommand(MenuKey(CharCode))
|
|
Else If GameUnderWay then PauseThisGame;{pause with any other key press}
|
|
End;
|
|
|
|
procedure TakeCareActivates(myEvent:EventRecord);
|
|
var
|
|
WhichWindow: WindowPtr;
|
|
Begin
|
|
WhichWindow := WindowPtr(myEvent.message);
|
|
SetPort(WhichWindow);
|
|
End;
|
|
|
|
procedure OneTimeGameStuff; {set up the gamestuff only needed on startup}
|
|
var
|
|
Dest: Point;
|
|
i,j,width,dh,dv,h,v:integer;
|
|
tRect:Rect;
|
|
Begin
|
|
SetRect(MouseRect,210,134,302,206); { this is for mapping control }
|
|
SetRect(DeltaRect,-4,-4,4,4); { this is for finding Pilot offset }
|
|
BorderRect := myWindow^.portRect; { limit pilot to this area }
|
|
InsetRect(BorderRect,10,10);{shrink by width of pilot}
|
|
MoveRect(BorderRect,0,0,1);{will use topleft}
|
|
|
|
SetRect(tRect,32,32,463,274); {inside rect of borderframes}
|
|
For i := 1 to 16 do begin
|
|
WindFrame[i] := tRect;{we'll let update draw the border}
|
|
InsetRect(tRect,-2,-2);
|
|
end;
|
|
|
|
OpenRgn;
|
|
FrameOval(InStar);
|
|
CloseRgn(StarRgn);{used as mask for drawing stars into chamber 'window'}
|
|
|
|
OpenRgn;
|
|
SetRect(tRect,0,0,105,105);
|
|
FrameOval(tRect);
|
|
CloseRgn(LimitRgn);{used to limit pilot.topleft movement inside chamber}
|
|
|
|
tRect := OffBigChamber;
|
|
InsetRect(tRect,13,13);
|
|
OpenRgn;
|
|
FrameOval(tRect);
|
|
CloseRgn(ChamberRgn); {used to mask Chamber}
|
|
|
|
tRect := OffFrame; {DoorFrame}
|
|
InsetRect(tRect,3,3);
|
|
OpenRgn;
|
|
FrameRect(tRect);
|
|
CloseRgn(DoorRgn); {used to mask door during slide open}
|
|
|
|
tRect := OffFrame; {DoorFrame}
|
|
OpenRgn;
|
|
FrameRect(tRect);
|
|
CloseRgn(DoorSlideRgn); {used to mask door during slide closed}
|
|
|
|
{Locate BigChamber !!!!! note: was (32,30) in small window}
|
|
OffSetRect(R[BigChamber],64,66);
|
|
|
|
{all other shapes are relative to R[BigChamber].topleft..call it 'Home'}
|
|
Home := R[BigChamber].topleft;
|
|
|
|
OpenRgn;
|
|
FrameOval(R[BigChamber]);
|
|
CloseRgn(BigChamberRgn);{mask when drawing onto screen}
|
|
|
|
OffSetRgn(StarRgn,Home.h+54-StarRgn^^.rgnBBox.left,
|
|
Home.v+54-StarRgn^^.rgnBBox.top);
|
|
StarBox := StarRgn^^.rgnBBox;
|
|
MoveRect(InStar,StarBox.right,StarBox.top,2); {InStar is dest.for OffStar}
|
|
|
|
R[Cover] := R[BigChamber];
|
|
InsetRect(R[Cover],4,4);{size of cover over the chamber}
|
|
TopCover := R[Cover];{locate... CloseTheCover.. will set proper size}
|
|
BotCover := R[Cover];
|
|
CloseTheCoverDoors;
|
|
|
|
OpenRgn;
|
|
FrameOval(R[Cover]);
|
|
CloseRgn(CoverRgn); {used to mask coverdoors}
|
|
|
|
i := 13; {this is amount Chamber is inset from R[BigChamber]}
|
|
OffSetRgn(ChamberRgn,Home.h + i-ChamberRgn^^.rgnBBox.left,
|
|
Home.v + i-ChamberRgn^^.rgnBBox.top);
|
|
|
|
OffSetRgn(LimitRgn,Home.h+12-LimitRgn^^.rgnBBox.left,
|
|
Home.v+12-LimitRgn^^.rgnBBox.top);
|
|
|
|
{create target rings...concentric regions with limitRgn as outside}
|
|
CopyRgn(LimitRgn,TargetRgn[3]);{copy of LimitRgn for extreme target edge}
|
|
|
|
For i := 3 downto 1 do begin
|
|
CopyRgn(TargetRgn[i],TargetRgn[i-1]);
|
|
InsetRgn(TargetRgn[i-1],10,10);
|
|
DiffRgn(TargetRgn[i],TargetRgn[i-1],TargetRgn[i]);
|
|
end;{for i}
|
|
|
|
MoveRect(R[Mask],Home.h+24,Home.v+24,1);
|
|
|
|
MoveRect(R[TargetBox],Home.h+147,Home.v-7,1);
|
|
MoveRect(TargetNum,R[TargetBox].left+14,R[TargetBox].top+17,1);
|
|
|
|
MoveRect(R[AirLock],Home.h+157,Home.v+47,1);
|
|
MoveRect(R[Door],Home.h+171,
|
|
Home.v+67,1);
|
|
OffSetRgn(DoorRgn,R[Door].left+3-DoorRgn^^.rgnBBox.left,
|
|
R[Door].top+3-DoorRgn^^.rgnBBox.top);
|
|
|
|
MoveRect(R[CntlBox],Home.h+208,
|
|
Home.v-14,1);
|
|
CntlCover := R[CntlBox];
|
|
InsetRect(CntlCover,3,3);{will cover controls during freeflight}
|
|
|
|
h := R[CntlBox].left + 9;
|
|
v := R[CntlBox].top + 6;
|
|
For i := 1 to 3 do begin
|
|
MoveControl(Radio[i],h,v);{locate Diff.buttons in Cntlbox}
|
|
v := v + 16;
|
|
end;{for i}
|
|
|
|
MoveRect(R[ScoreBox],Home.h+313,Home.v-14,1);
|
|
{locate the four score areas in scorebox}
|
|
|
|
BonusRect := R[ScoreBox];
|
|
OffSetRect(BonusRect,3,16);{move topleft to bonus rect}
|
|
BonusRect.right := BonusRect.left + 62;
|
|
BonusRect.bottom := BonusRect.top + 18;
|
|
tinyBonus := BonusRect;
|
|
InsetRect(tinyBonus,7,5);{inset to reduce erase area,calculation for text}
|
|
PenaltyRect := BonusRect;
|
|
OffSetRect(PenaltyRect,0,41);
|
|
tinyPenalty := PenaltyRect;
|
|
InsetRect(tinyPenalty,7,5);
|
|
ScoreRect := PenaltyRect;
|
|
OffSetRect(ScoreRect,0,41);
|
|
tinyScore := ScoreRect;
|
|
InsetRect(tinyScore,7,5);
|
|
LoScoreRect := ScoreRect;
|
|
OffSetRect(LoScoreRect,0,41);
|
|
tinyLoScore := LoScoreRect;
|
|
InsetRect(tinyLoScore,7,5);
|
|
|
|
MoveRect(R[TimerBox],Home.h+19,Home.v+166,1);
|
|
MoveRect(R[Title],R[TimerBox].left,R[TimerBox].top,1);{title on top of Timerbox}
|
|
SetRect(TimeSlide,0,0,99,7);{size of rect inside TimerBox}
|
|
MoveRect(TimeSlide,R[TimerBox].left+5,R[TimerBox].top+11,1);
|
|
MoveRect(R[Pod],Home.h+252,Home.v+144,1);
|
|
MoveRect(MouseRect,R[Pod].left-50,R[Pod].top-35,1);{center mouse on R[Pod]}
|
|
|
|
Difficulty := 1;{Radio buttons come with 1 preset,IsSoEasy value = 1}
|
|
|
|
CreateLoScoreStuff;
|
|
NameString := 'Pilot';{will start with pilot then use user input}
|
|
GetDItem(myDialog[Name],4,i,NameHandle,tRect);{get handle to text item}
|
|
{get handle to controls,Calculate LoScore buttons}
|
|
For i := 2 to 3 do GetDItem(myDialog[LScore],i,j,
|
|
ScoreControl[i],tRect);
|
|
SetCtlValue(ControlHandle(ScoreControl[2]),1);{set control true}
|
|
FigureLoScore := True;{flag to true,we will calculate LoScores as default}
|
|
Penalty := 0;
|
|
Bonus := 0;
|
|
AvgScore := 0.0;
|
|
PauseUnderWay := False;
|
|
PilotStatus := Resting;{for proper update drawing}
|
|
|
|
CopyBits(OffScreen,InScreen,OffBigChamber,R[BigChamber],srcCopy,nil);
|
|
|
|
End; { of OneTimeGameStuff }
|
|
|
|
procedure MapMouseToDelta;
|
|
{change current mouse location into offset for pilot..Dh,Dv}
|
|
Begin
|
|
If FlipInProgress and (PilotStatus <> FreeFlight) then SetPt(MouseLoc,0,0)
|
|
Else begin {get user mouse input}
|
|
GetMouse(MouseLoc); { MouseLoc in Coords of currentGrafPort }
|
|
|
|
{if out of bounds then limit MouseLoc to MouseRect extremes }
|
|
If MouseLoc.h > MouseRect.right then MouseLoc.h := MouseRect.right
|
|
else If MouseLoc.h < MouseRect.left then MouseLoc.h := MouseRect.left;
|
|
|
|
If MouseLoc.v > MouseRect.bottom then MouseLoc.v := MouseRect.bottom
|
|
else If MouseLoc.v < MouseRect.top then MouseLoc.v := MouseRect.top;
|
|
|
|
{now map MouseLoc from MouseRect into DeltaRect...MouseLoc becomes
|
|
request from user for new Offset for Pilot}
|
|
MapPt(MouseLoc,MouseRect,DeltaRect);{great!,thanks to Bill Atkinson}
|
|
end;{else}
|
|
{we want change of direction to be smooth so 'damp' by letting MouseLoc
|
|
change Dh,Dv only one unit per loop.}
|
|
If MouseLoc.h>Dh then inc(Dh) {MouseLoc.h won't be over 4 or under -4}
|
|
else if MouseLoc.h < Dh then dec(Dh);
|
|
If MouseLoc.v > Dv then inc(Dv)
|
|
else if MouseLoc.v < Dv then dec(Dv);{Dh,Dv are rate of pilot movement}
|
|
end;
|
|
|
|
procedure AnimateStuffInCommon;{for both OneLoop & CoverDoors}
|
|
Begin
|
|
{test if new location is ok... not outside the chamber area}
|
|
tPoint.h := R[Pilot].left + Nh;{tPoint = temporary new pilot location}
|
|
tPoint.v := R[Pilot].top + Nv;
|
|
If not(PtInRgn(tPoint,LimitRgn)) then begin {new pilot is outside the Chamber!}
|
|
Repeat
|
|
Nh := Nh div 2;{move half way back to last pilot location}
|
|
Nv := Nv div 2;
|
|
tPoint.h := R[Pilot].left + Nh;
|
|
tPoint.v := R[Pilot].top + Nv;
|
|
Until(PtInRgn(tPoint,LimitRgn));{half offset until back inside limitRgn}
|
|
|
|
inc(Penalty);{add to penalty,does nothing in CoverDoors}
|
|
|
|
If SoundOn and (WhichSound <> Buzz) then begin {write out a buzzsound}
|
|
err := PBKillIO(SoundParmBlk,false);{kill current sound}
|
|
WriteASoundBlock(ptr(Sound[Buzz]),Buff[Buzz],TickCount);
|
|
WhichSound := Buzz;
|
|
end;{if soundOn}
|
|
end;{of if not PtInRect}
|
|
|
|
{locate our 3 rects which move in sequence}
|
|
R[Pilot].left := R[Pilot].left + Nh; {faster than an OffsetRect}
|
|
R[Pilot].right := R[Pilot].right + Nh;
|
|
R[Pilot].top := R[Pilot].top + Nv;
|
|
R[Pilot].bottom := R[Pilot].bottom + Nv;
|
|
|
|
OffPatch.left := OffPatch.left + Nh; {faster than an OffsetRect}
|
|
OffPatch.right := OffPatch.right + Nh;
|
|
OffPatch.top := OffPatch.top + Nv;
|
|
OffPatch.bottom := OffPatch.bottom + Nv;
|
|
|
|
OffPilotMask.left := OffPilotMask.left + Nh; {faster than an OffsetRect}
|
|
OffPilotMask.right := OffPilotMask.right + Nh;
|
|
OffPilotMask.top := OffPilotMask.top + Nv;
|
|
OffPilotMask.bottom := OffPilotMask.bottom + Nv;
|
|
|
|
{which shape to draw?,PilotNdx points to one of 9 shapes}
|
|
If not(FlipInProgress) then begin
|
|
If MouseLoc.h = 0 then PilotNdx.h := 2
|
|
else if MouseLoc.h > 0 then PilotNdx.h := 3 else PilotNdx.h := 1;
|
|
If MouseLoc.v = 0 then PilotNdx.v := 2
|
|
else if MouseLoc.v > 0 then PilotNdx.v := 3 else PilotNdx.v := 1;
|
|
end;{if not flip}
|
|
|
|
If OffStarWindow.left = OffStar.left then
|
|
OffSetRect(OffStarWindow,OffStar.right-OffStarWindow.right,0)
|
|
Else OffSetRect(OffStarWindow,-1,0);{so we can animate our stars}
|
|
|
|
{score ....start in center, if pilot is there fall thru else try next,
|
|
TargetRgn is an array of concentric rings}
|
|
SubScore := 0;
|
|
While (not(PtInRgn(R[Pilot].topleft,TargetRgn[SubScore]))) do begin
|
|
inc(SubScore); {find if pilot is in 0-3 target circles}
|
|
end;
|
|
|
|
CopyBits(OffScreen,myWindow^.portBits,OffNumeral[SubScore],
|
|
TargetNum,srcCopy,nil);{proper numeral into target box}
|
|
end;{of procedure}
|
|
|
|
procedure DrawTheCoverDoors;
|
|
Begin
|
|
OldBits := myWindow^.portBits;
|
|
SetPortBits(InScreen);
|
|
|
|
FillRect(TopCover,dkGray);
|
|
FillRect(BotCover,dkGray);
|
|
MoveTo(TopCover.left,TopCover.bottom);
|
|
LineTo(TopCover.right,TopCover.bottom);
|
|
MoveTo(BotCover.left,BotCover.top);
|
|
LineTo(BotCover.right,BotCover.top);
|
|
|
|
SetRectRgn(tRgn,TopCover.left,TopCover.bottom,TopCover.right,BotCover.top);
|
|
DiffRgn(CoverRgn,tRgn,tRgn);{find area for mask on coverdoors}
|
|
CopyBits(OffScreen,InScreen,OffMask,R[BigChamber],srcBic,tRgn);
|
|
|
|
SetPortBits(OldBits);
|
|
CopyBits(InScreen,myWindow^.portBits,R[Cover],R[Cover],srcCopy,CoverRgn);
|
|
end;
|
|
|
|
procedure AnimateOneLoop;{this is the main game loop}
|
|
var
|
|
i,j:integer;
|
|
tRect: Rect;
|
|
Begin
|
|
{OffPatch floats over OffBigChamber..used to restore background over
|
|
last pilot in InScreen}
|
|
CopyBits(OffScreen,InScreen,OffPatch,R[Pilot],srcCopy,nil);
|
|
lastPilot := R[Pilot];{keep a temporary copy of our last R[Pilot]}
|
|
|
|
MapMouseToDelta;{get new Dh,Dv for pilot}
|
|
|
|
If Sustain <1 then begin {then go get another Grav record,new force}
|
|
Gh := Grav[GravNdx].magH;
|
|
Gv := Grav[GravNdx].magV;
|
|
Sustain := Grav[GravNdx].duration;{how many loops will grav work}
|
|
|
|
FillOval(Lights[LightNdx],dkgray);{erase last light}
|
|
LightNdx := Grav[GravNdx].liteNdx;{get next light index}
|
|
EraseOval(Lights[LightNdx]);
|
|
FrameOval(Lights[LightNdx]);{turn on new light}
|
|
If SoundOn then begin {write a Tone Sound for new force}
|
|
err := PBKillIO(SoundParmBlk,false);{kill current sound}
|
|
i := abs(Gh) + abs(Gv);{watch out for zero magnitude}
|
|
Sound[GravTone]^.count := FixRatio(i,2);{let magnitude influence GravTone}
|
|
WriteASoundBlock(ptr(Sound[GravTone]),Buff[GravTone],TickCount);
|
|
end;{if soundOn}
|
|
If GravNdx < 30 then inc(GravNdx) else GravNdx := 1;{30 elements in array}
|
|
end{if Sustain}
|
|
Else dec(Sustain);
|
|
Nh := Dh + Gh;{net effect of flight control and gravity}
|
|
Nv := Dv + Gv;
|
|
|
|
AnimateStuffInCommon;{stuff in common to OneLoop and CoverDoors}
|
|
|
|
Penalty := Penalty + SubScore;
|
|
inc(LoopCount);
|
|
DrawIntegerIntoBox(Penalty,tinyPenalty);
|
|
AvgScore := (Penalty - Bonus)/LoopCount;
|
|
If AvgScore < 0 then AvgScore := 0;
|
|
DrawScoreIntoBox(AvgScore,tinyScore);
|
|
|
|
CopyBits(OffScreen,InScreen,OffStarWindow,InStar,srcCopy,StarRgn);
|
|
|
|
If FlipInProgress then begin {draw the Pilot flip shapes, get next}
|
|
CopyBits(OffScreen,InScreen,OffFlip[PilotNdx.h],
|
|
R[Pilot],notSrcBic,nil);
|
|
If RotateRight then
|
|
If PilotNdx.h < 7 then inc(PilotNdx.h) {next flip shape}
|
|
else begin
|
|
FlipInProgress := False; {flip is over.. reset normal status}
|
|
Bonus := Bonus + Difficulty;{more points for higher level}
|
|
DrawIntegerIntoBox(Bonus,tinyBonus);
|
|
end{else}
|
|
else
|
|
If PilotNdx.h > 1 then dec(PilotNdx.h) {next flip shape}
|
|
else begin
|
|
FlipInProgress := False; {flip is over.. reset normal status}
|
|
Bonus := Bonus + Difficulty;
|
|
DrawIntegerIntoBox(Bonus,tinyBonus);
|
|
end;{else}
|
|
end { if flipinprogress}
|
|
Else {normal pilot... not flipping}
|
|
CopyBits(OffScreen,InScreen,OffPilot[PilotNdx.h,PilotNdx.v],
|
|
R[Pilot],notSrcBic,nil); {modes on page i-157}
|
|
|
|
{copy pilot sized piece of mask over the new pilot,OffPilotMask
|
|
floats over OffMask shape in synch with Pilot and OffPatch}
|
|
CopyBits(OffScreen,InScreen,OffPilotMask,R[Pilot],srcOr,nil);
|
|
|
|
UnionRect(LastPilot,R[Pilot],LastPilot);{rect that contains both Pilots}
|
|
UnionRect(LastPilot,Instar,LastPilot); {find rect that contains pilots & Stars}
|
|
|
|
CopyBits(InScreen,myWindow^.portBits,LastPilot,
|
|
LastPilot,srcCopy,ChamberRgn);
|
|
|
|
{monitor our game time...indicator below chamber}
|
|
If (LoopCount mod 6 = 0) then begin {we only draw a line every 6 loops}
|
|
inc(TimeLine);{one step closer to ending game}
|
|
|
|
If TimeLine = TimeSlide.right then begin {then end this game }
|
|
GameUnderWay := False; { halt animation }
|
|
PilotStatus := Resting;{for draw update stuff}
|
|
err := PBKillIO(SoundParmBlk,false);
|
|
WhichSound := Silence;
|
|
ShowCursor;
|
|
DeleteMenu(MessageMenu); {remove exit message,i-354}
|
|
For i := 1 to 4 do EnableItem(myMenus[i],0);{show other menu options}
|
|
DrawMenuBar;
|
|
FillOval(Lights[LightNdx],dkGray);{erase last light}
|
|
FillRect(TargetNum,Gray);{Cover last Num...}
|
|
CloseTheCoverDoors;
|
|
DrawTheCoverDoors;{draw cover & mask}
|
|
|
|
CopyBits(OffScreen,myWindow^.portBits,OffPod[2],
|
|
R[Pod],srcCopy,nil);
|
|
If (AvgScore < LoScore^[Difficulty,3].score) and
|
|
FigureLoScore then ProcessNewLoScore;
|
|
For i := 1 to 3 do HiliteControl(Radio[i],0);{enable controls}
|
|
InvalRect(CntlCover);{will force redraw of controls}
|
|
InvalRect(R[Title]);{will force redraw of Title over TimerBox}
|
|
end{then begin}
|
|
Else begin
|
|
moveTo(TimeLine,TimeSlide.top);
|
|
LineTo(TimeLine,TimeSlide.bottom);{draw the indicator line in timerbox}
|
|
end;{else}
|
|
end;{if LoopCount mod 6}
|
|
End;{of procedure}
|
|
|
|
procedure AnimateFreeFlight;{animate Pilot over the entire window}
|
|
var
|
|
i,j:integer;
|
|
tRect: Rect;
|
|
Where:Longint;
|
|
Begin
|
|
MapMouseToDelta;
|
|
|
|
tRect := R[BigPilot];{keep last location in temporaryRect}
|
|
R[BigPilot].left := R[BigPilot].left + Dh; {faster than an OffsetRect}
|
|
R[BigPilot].right := R[BigPilot].right + Dh;
|
|
R[BigPilot].top := R[BigPilot].top + Dv;
|
|
R[BigPilot].bottom := R[BigPilot].bottom + Dv;
|
|
|
|
If not(PtInRect(R[BigPilot].topleft,BorderRect)) then begin{outside,find which}
|
|
If R[BigPilot].left > BorderRect.right then
|
|
OffSetRect(R[BigPilot],BorderRect.right-R[BigPilot].left,0);
|
|
If R[BigPilot].left < BorderRect.left then
|
|
OffSetRect(R[BigPilot],BorderRect.left-R[BigPilot].left,0);
|
|
If R[BigPilot].top > BorderRect.bottom then
|
|
OffSetRect(R[BigPilot],0,BorderRect.bottom-R[BigPilot].top);
|
|
If R[BigPilot].top < BorderRect.top then
|
|
OffSetRect(R[BigPilot],0,BorderRect.top-R[BigPilot].top);
|
|
end;{of if not PtInRect}
|
|
|
|
{which shape to draw?}
|
|
If not(FlipInProgress) {no flip} then begin
|
|
If MouseLoc.h = 0 then PilotNdx.h := 2
|
|
else if MouseLoc.h > 0 then PilotNdx.h := 3 else PilotNdx.h := 1;
|
|
If MouseLoc.v = 0 then PilotNdx.v := 2
|
|
else if MouseLoc.v > 0 then PilotNdx.v := 3 else PilotNdx.v := 1;
|
|
end;{if not flip}
|
|
|
|
CopyBits(OffScreen,InScreen,OffHold,tRect,srcCopy,nil);{restore inscreen}
|
|
CopyBits(InScreen,OffScreen,R[BigPilot],OffHold,srcCopy,nil);{save current}
|
|
|
|
If FlipInProgress then begin
|
|
CopyBits(OffScreen,InScreen,OffBigFlip[PilotNdx.h],
|
|
R[BigPilot],notSrcBic,nil);
|
|
If RotateRight then
|
|
If PilotNdx.h < 7 then inc(PilotNdx.h) {next flip shape}
|
|
else FlipInProgress := False {flip is over.. reset freeflight status}
|
|
else
|
|
If PilotNdx.h > 1 then dec(PilotNdx.h) {next flip shape}
|
|
else FlipInProgress := False;{flip is over.. reset freeflight status}
|
|
end { if FlipInProgress}
|
|
Else {normal pilot... not flipping}
|
|
CopyBits(OffScreen,InScreen,OffBigPilot[PilotNdx.h,PilotNdx.v],
|
|
R[BigPilot],notSrcBic,nil);
|
|
|
|
UnionRect(tRect,R[BigPilot],tRect);{Rect to contain both last and current}
|
|
|
|
CopyBits(InScreen,myWindow^.portBits,tRect,tRect,srcCopy,nil);
|
|
|
|
If LoopCount < 7 then inc(LoopCount)
|
|
else begin
|
|
InvertRect(R[Door]);{flashing Airlock door stuff}
|
|
LoopCount := 1;
|
|
{take care of offscreen stuff in case of invert on screen}
|
|
CopyBits(OffScreen,InScreen,OffHold,R[BigPilot],srcCopy,nil);{restore inscreen}
|
|
OldBits := myWindow^.portBits;
|
|
SetPortBits(InScreen);
|
|
InvertRect(R[Door]);{invert the patched Door in InScreen bitmap}
|
|
SetPortBits(OldBits);
|
|
CopyBits(InScreen,OffScreen,R[BigPilot],OffHold,srcCopy,nil);{save current}
|
|
end;
|
|
|
|
End;{of procedure}
|
|
|
|
procedure DrawAirLockShapes;{tRgn masks frame over or behind pilot}
|
|
Begin
|
|
CopyBits(OffScreen,InScreen,OffFrame,R[Door],srcCopy,nil);
|
|
CopyBits(OffScreen,InScreen,OffDoorSlide,R[Door],srcCopy,DoorRgn);
|
|
CopyBits(OffScreen,InScreen,OffBigPilot[PilotNdx.h,PilotNdx.v],
|
|
R[BigPilot],notsrcBic,tRgn);
|
|
CopyBits(InScreen,myWindow^.portBits,R[Door],R[Door],srcCopy,nil);
|
|
end;
|
|
|
|
procedure AnimateAirLock;
|
|
var
|
|
i,j:integer;
|
|
MouseLoc,tpoint: Point;
|
|
tRect: Rect;
|
|
Begin
|
|
{find random movement for our Pilot while door is opening/closing}
|
|
SetPt(MouseLoc,Random div (Maxint div 2),Random div (Maxint div 2));
|
|
If MouseLoc.h>Dh then inc(Dh) {MouseLoc.h won't be over 4 or under -4}
|
|
else if MouseLoc.h < Dh then dec(Dh);
|
|
If MouseLoc.v > Dv then inc(Dv)
|
|
else if MouseLoc.v < Dv then dec(Dv);{Dh,Dv are rate of pilot movement}
|
|
|
|
R[BigPilot].left := R[BigPilot].left + Dh; {faster than an OffsetRect}
|
|
R[BigPilot].right := R[BigPilot].right + Dh;
|
|
R[BigPilot].top := R[BigPilot].top + Dv;
|
|
R[BigPilot].bottom := R[BigPilot].bottom + Dv;
|
|
|
|
If R[BigPilot].left < R[Door].left then
|
|
OffSetRect(R[BigPilot],R[Door].left-R[BigPilot].left,0)
|
|
else If R[BigPilot].right > R[Door].right then
|
|
OffSetRect(R[BigPilot],R[Door].right-R[BigPilot].right,0);
|
|
If R[BigPilot].top < R[Door].top then
|
|
OffSetRect(R[BigPilot],0,R[Door].top-R[BigPilot].top)
|
|
else If R[BigPilot].bottom > R[Door].bottom then
|
|
OffSetRect(R[BigPilot],0,R[Door].bottom-R[BigPilot].bottom);
|
|
|
|
If DoorOpening then begin {The door is opening}
|
|
If OffDoorSlide.left > OffDoor.left then begin {still sliding}
|
|
OffSetRect(OffDoorSlide,-1,0); {move it one to left}
|
|
RectRgn(tRgn,myWindow^.portRect);{whole screen,just so its not nil}
|
|
DrawAirLockShapes;
|
|
|
|
end {if still sliding}
|
|
else begin {begin door closing stuff}
|
|
OffSetRgn(DoorSlideRgn,R[Door].right-DoorSlideRgn^^.rgnBBox.left,
|
|
R[Door].top-DoorSlideRgn^^.rgnBBox.top);{will mask pilot}
|
|
DoorOpening := False;
|
|
end;{else}
|
|
end {door is opening}
|
|
Else begin {Door is Closing}
|
|
If OffDoorSlide.right < OffDoor.right then begin {still sliding}
|
|
OffSetRect(OffDoorSlide,1,0); {move it one to right}
|
|
OffSetRgn(DoorSlideRgn,-1,0); {move it to left, will hide pilot}
|
|
DiffRgn(DoorRgn,DoorSlideRgn,tRgn);{pilot appears to be behind door}
|
|
|
|
DrawAirLockShapes;
|
|
|
|
end {if still sliding}
|
|
else InitialThisGame;{will begin coverdoor sequence and game}
|
|
end; {else door is closing}
|
|
End; { of procedure }
|
|
|
|
procedure AnimateCoverDoors;
|
|
var
|
|
i,j:integer;
|
|
tRect: Rect;
|
|
Begin
|
|
MapMouseToDelta;
|
|
Nh := Dh;{net force and flight effects on Pilot}
|
|
Nv := Dv;
|
|
|
|
AnimateStuffInCommon;
|
|
|
|
CopyBits(OffScreen,InScreen,OffBigChamber,R[BigChamber],srcCopy,nil);
|
|
CopyBits(OffScreen,InScreen,OffStarWindow,InStar,srcCopy,StarRgn);
|
|
|
|
If FlipInProgress then begin
|
|
CopyBits(OffScreen,InScreen,OffFlip[PilotNdx.h],
|
|
R[Pilot],notSrcBic,nil); {modes on page i-157}
|
|
If RotateRight then
|
|
If PilotNdx.h < 7 then inc(PilotNdx.h) {next flip shape}
|
|
else FlipInProgress := False {flip is over.. reset normal status}
|
|
else
|
|
If PilotNdx.h > 1 then dec(PilotNdx.h) {next flip shape}
|
|
else FlipInProgress := False; {flip is over.. reset normal status}
|
|
end { if flipinprogress}
|
|
Else {normal pilot... not flipping}
|
|
CopyBits(OffScreen,InScreen,OffPilot[PilotNdx.h,PilotNdx.v],
|
|
R[Pilot],notSrcBic,nil); {modes on page i-157}
|
|
|
|
{copy just pilot sized piece of mask over the new pilot}
|
|
CopyBits(OffScreen,InScreen,OffPilotMask,R[Pilot],srcOr,nil);
|
|
|
|
TopCover.bottom := TopCover.bottom - 3;
|
|
BotCover.top := BotCover.top + 3;
|
|
|
|
DrawTheCoverDoors;
|
|
|
|
If CoverLoops > 0 then dec(CoverLoops)
|
|
Else begin
|
|
PilotStatus := InChamber;{doors are open so begin the game animation}
|
|
EraseRect(BonusRect);
|
|
EraseRect(PenaltyRect);
|
|
EraseRect(ScoreRect);
|
|
EraseRect(LoScoreRect);
|
|
EraseRect(CntlCover);
|
|
For i := 1 to 3 do ShowControl(Radio[i]);
|
|
DrawScoreIntoBox(LoScore^[Difficulty,1].score,tinyLoScore);
|
|
CopyBits(OffScreen,myWindow^.portBits,OffTimerBox,
|
|
R[TimerBox],srcCopy,nil);{will erase Titlebox}
|
|
{sequence OffPatch and OffPilotMask with current R[Pilot]}
|
|
i := R[Pilot].left - Home.h;
|
|
j := R[Pilot].top - Home.v;
|
|
MoveRect(OffPatch,OffBigChamber.left+i,OffBigChamber.top+j,1);
|
|
err := PBKillIO(SoundParmBlk,false);{kill CoverDoors sound}
|
|
WhichSound := Game; {will start GameSound}
|
|
end;{of Else}
|
|
End;{of procedure}
|
|
|
|
procedure CreateLightsArray;{array of 17 rects around chamber}
|
|
var
|
|
dir:real;
|
|
mag,i,centerH,
|
|
centerV: integer;
|
|
tpoint: Point;
|
|
tRect:Rect;
|
|
begin
|
|
SetRect(tRect,0,0,12,12);
|
|
dir := 0;
|
|
mag := 84;{radius to center of buttons}
|
|
centerh := R[BigChamber].left + ((R[BigChamber].right-R[BigChamber].left) div 2);
|
|
centerV := R[BigChamber].top + ((R[BigChamber].right-R[BigChamber].left) div 2);
|
|
|
|
For i := 0 to 15 do begin
|
|
tPoint.h := round(mag * cos(i*2*Pi/16.0))+centerH-6;{-6 for half tRect}
|
|
tPoint.v := round(mag * sin(i*2*Pi/16.0))+centerV-6;
|
|
MoveRect(tRect,tpoint.h,tpoint.v,1);
|
|
Lights[i] := tRect;
|
|
end; {for i :=}
|
|
Lights[16] := Lights[0]; {0 radians is same as 2*Pi radians}
|
|
end;
|
|
|
|
Procedure DrawUpDateStuff;
|
|
{will draw all our images in response to Update event,an Update event is
|
|
waiting for our newly opened window so will draw our first stuff too!}
|
|
var
|
|
tRect: Rect;
|
|
tpoint: Point;
|
|
i: integer;
|
|
Begin
|
|
{if the game is paused the screen has been saved in InScreen Bitmap}
|
|
If PauseUnderWay then CopyBits(InScreen,myWindow^.portBits,
|
|
InScreen.bounds,myWindow^.portRect,srcCopy,nil) {restore screen}
|
|
Else begin
|
|
For i := 16 downto 2 do FrameRect(WindFrame[i]);
|
|
FillRect(WindFrame[1],dkgray);
|
|
FrameRect(WindFrame[1]);
|
|
|
|
CopyBits(OffScreen,myWindow^.portBits,OffBigChamber,
|
|
R[BigChamber],srcCopy,BigChamberRgn);
|
|
|
|
DrawTheCoverDoors;{draw the Covers}
|
|
|
|
For i := 0 to 15 do begin
|
|
FillOval(Lights[i],dkgray);
|
|
end;{for i :=}
|
|
|
|
CopyBits(OffScreen,myWindow^.portBits,OffTargetBox,
|
|
R[TargetBox],srcCopy,nil);
|
|
CopyBits(OffScreen,myWindow^.portBits,OffAirLock,
|
|
R[AirLock],srcCopy,nil);
|
|
DrawPicture(pPict[CntlBox],R[CntlBox]);
|
|
If PilotStatus = FreeFlight then FillRect(CntlCover,gray);{update during freeflight}
|
|
CopyBits(OffScreen,myWindow^.portBits,OffScoreBox,
|
|
R[ScoreBox],srcCopy,nil);
|
|
|
|
CopyBits(OffScreen,myWindow^.portBits,OffFrame,
|
|
R[Door],srcCopy,nil);
|
|
CopyBits(OffScreen,myWindow^.portBits,OffDoorSlide,
|
|
R[Door],srcCopy,DoorRgn);{mask to inside of door frame}
|
|
|
|
Case PilotStatus of
|
|
InChamber:Begin {draw the timerBox instead of title,due to Switcher}
|
|
CopyBits(OffScreen,myWindow^.portBits,OffTimerBox,
|
|
R[TimerBox],srcCopy,nil);
|
|
tRect := TimeSlide;{indicator area}
|
|
tRect.right := TimeLine + 1;
|
|
FillRect(tRect,black);
|
|
end;{InChamber}
|
|
Otherwise CopyBits(OffScreen,myWindow^.portBits,OffTitle,
|
|
R[Title],srcCopy,nil);
|
|
end;{case Pilotstatus}
|
|
|
|
CopyBits(OffScreen,myWindow^.portBits,OffPod[2],
|
|
R[Pod],srcCopy,nil);
|
|
|
|
DrawIntegerIntoBox(Penalty,tinyPenalty);
|
|
DrawIntegerIntoBox(Bonus,tinyBonus);
|
|
DrawScoreIntoBox(AvgScore,tinyScore);
|
|
DrawScoreIntoBox(LoScore^[Difficulty,1].score,tinyLoScore);
|
|
end;{of Else}
|
|
end;
|
|
|
|
procedure TakeCareUpdates(Event:EventRecord);
|
|
var
|
|
UpDateWindow,TempPort: WindowPtr;
|
|
itemHit: integer;
|
|
Test: Boolean;
|
|
Begin
|
|
UpDateWindow := WindowPtr(Event.message);
|
|
GetPort(TempPort);
|
|
SetPort(UpDateWindow);
|
|
BeginUpDate(UpDateWindow);
|
|
EraseRect(UpDateWindow^.portRect);
|
|
If UpDateWindow = myWindow then DrawUpDateStuff;
|
|
DrawControls(UpDateWindow);
|
|
EndUpDate(UpDateWindow);
|
|
SetPort(TempPort);
|
|
End;
|
|
|
|
procedure TakeCareSoundStuff;
|
|
Begin
|
|
If SoundParmBlk^.ioResult < 1 then {sound is finished find another/play it}
|
|
Case WhichSound of
|
|
Blue: InitialFourToneSound; {Waltz quit.. so start again}
|
|
|
|
Buzz:begin {buzz pilot touching wall sound,finished so go back to game}
|
|
WhichSound := Game;
|
|
WriteASoundBlock(ptr(Sound[Game]),Buff[Game],TickCount);
|
|
end;{buzz}
|
|
|
|
AirDoor,BigDoor,Game:
|
|
WriteASoundBlock(ptr(Sound[WhichSound]),Buff[WhichSound],TickCount);
|
|
end {of case WhichSound}
|
|
Else If (WhichSound = Blue) and (TickCount > ToneDelay) then begin
|
|
inc(NoteCount);
|
|
BlueSound^.sound1Rate := mySongPtr^.pitch[NoteCount,1];
|
|
BlueSound^.sound2Rate := mySongPtr^.pitch[NoteCount,2];
|
|
BlueSound^.sound3Rate := mySongPtr^.pitch[NoteCount,3];
|
|
BlueSound^.sound4Rate := mySongPtr^.pitch[NoteCount,4];
|
|
BlueSound^.duration := 80;
|
|
|
|
ToneDelay := mySongPtr^.duration[NoteCount] + TickCount;
|
|
|
|
If mySongPtr^.noteCount = NoteCount then NoteCount := 0;
|
|
|
|
end; {if TickCount}
|
|
End;{of procedure}
|
|
|
|
procedure MainEventLoop;
|
|
var
|
|
myEvent: EventRecord;
|
|
i: integer;
|
|
Begin
|
|
InitCursor;
|
|
Repeat
|
|
SystemTask;
|
|
If GetNextEvent(EveryEvent,myEvent) then
|
|
Case myEvent.What of
|
|
mouseDown: TakeCareMouseDown(myEvent);
|
|
KeyDown: TakeCareKeyDown(myEvent);
|
|
ActivateEvt:TakeCareActivates(myEvent);
|
|
UpdateEvt:TakeCareUpdates(myEvent);
|
|
End {of Case}
|
|
Else {no event pending so lets do some game stuff}
|
|
Begin
|
|
If GameUnderWay then begin
|
|
Case PilotStatus of
|
|
InChamber: AnimateOneLoop;{animate Pilot in chamber, gamestuff}
|
|
OpenDoors: AnimateCoverDoors;{animate Chamber doors opening}
|
|
FreeFlight:begin {animate Pilot over entire window}
|
|
If not(SoundOn) then begin
|
|
aTick := TickCount;
|
|
Repeat Until(TickCount > aTick + 2);{slow down}
|
|
end;
|
|
AnimateFreeFlight;
|
|
end;{case 3};
|
|
EnterLock:begin {animate pilot entering airlock door}
|
|
If not(SoundOn) then begin
|
|
aTick := TickCount;
|
|
Repeat Until(TickCount > aTick + 1);{slow down}
|
|
end;
|
|
AnimateAirLock;
|
|
end;{case 4}
|
|
end;{case PilotStatus}
|
|
|
|
If SoundOn then TakeCareSoundStuff;
|
|
|
|
end { if GameUnderWay}
|
|
|
|
End; {else no event pending}
|
|
Until Finished;
|
|
End;
|
|
|
|
procedure SetUpMenus;
|
|
var
|
|
i: integer;
|
|
Begin
|
|
myMenus[1] := GetMenu(appleMenu); {get menu info from resources}
|
|
AddResMenu(myMenus[1],'DRVR'); {add in all the DA's}
|
|
myMenus[2] := GetMenu(fileMenu);
|
|
myMenus[3] := GetMenu(optionMenu);
|
|
myMenus[4] := GetMenu(worksMenu);
|
|
myMenus[5] := GetMenu(MessageMenu); {this is the backspace message}
|
|
CheckItem(myMenus[3],3,True); {check the Sound item}
|
|
SoundOn := True; {sound will start on first begin}
|
|
For i := 1 to 4 do
|
|
begin
|
|
InsertMenu(myMenus[i],0);
|
|
end;
|
|
DrawMenuBar;
|
|
End;
|
|
|
|
procedure CloseStuff;
|
|
var i:integer;
|
|
Begin
|
|
err := PBKillIO(SoundParmBlk,false);{kill sound before quitting}
|
|
WriteResource(ScoreHandle);{write out if changes were flagged..LoScore}
|
|
End;
|
|
|
|
PROCEDURE InitThings;
|
|
Begin
|
|
InitGraf(@thePort); {create a grafport for the screen}
|
|
|
|
MoreMasters; {extra pointer blocks at the bottom of the heap}
|
|
MoreMasters; {this is 5 X 64 master pointers}
|
|
MoreMasters;
|
|
MoreMasters;
|
|
MoreMasters;
|
|
|
|
{get the cursors we use and lock them down - no clutter}
|
|
ClockCursor := GetCursor(watchCursor);
|
|
HLock(Handle(ClockCursor));
|
|
|
|
{show the watch while we wait for inits & setups}
|
|
SetCursor(ClockCursor^^);
|
|
|
|
{init everything in case the app is the Startup App}
|
|
InitFonts;
|
|
InitWindows;
|
|
InitMenus;
|
|
TEInit;{for the Dialog stuff}
|
|
InitDialogs(Nil);
|
|
|
|
Finished := False; {set terminator to false}
|
|
FlushEvents(everyEvent,0); {clear events}
|
|
Screen := ScreenBits.Bounds; { Get screen dimensions from thePort }
|
|
End;
|
|
|
|
{Main Program begins here}
|
|
BEGIN
|
|
InitThings;
|
|
SetUpMenus;
|
|
CreateWindow; {load window,dialogs}
|
|
CreateControls; {our buttons, and radio controls}
|
|
CreateRegions; {newRgn for all our regions}
|
|
CreateOffScreenBitMap; {see Apple tech note 41,create OffScreen,InScreen}
|
|
CreatePictures; {load pictures from resources}
|
|
DrawPicsIntoOffScreen;{draw the pics into the OffScreen Bitmap}
|
|
CreateOffScreenRects; {set all rectangles for 'copybits' shape drawing}
|
|
CreateSound; {create all the sound buffers, etc}
|
|
OneTimeGameStuff; {Game varibles, scorebox stuff,etc}
|
|
CreateLightsArray; {array of rects for drawing indicator lights}
|
|
GameUnderWay := False;{click on Pod will begin a game sequence, mousedown event}
|
|
WhichSound := Silence;
|
|
For Dh := 1 to 3 do ShowControl(Radio[Dh]);{these are our difficulty controls}
|
|
MainEventLoop; {manage all user input until quit}
|
|
CloseStuff; {do this before quitting... always kill sound before quit}
|
|
END.
|