home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / diverace.zip / SOURCE.ZIP / source / work / diverace.pas < prev    next >
Pascal/Delphi Source File  |  1995-08-28  |  59KB  |  2,083 lines

  1. (***************************************************************************
  2.   DIVERACE a Game-Programming example for Virtual Pascal.
  3.  
  4.   Author  :  Michael Mrosowski
  5.              Fidonet:  2:240/5022.1
  6.              EMail:    lagaffe@offline.sh.sub.de
  7.  
  8.   Last Chg:  19.08.95
  9.  
  10.   This game and the sourcecode, as far as it is not copyrighted by other
  11.   parties is free for use. It is released for the purpose to promote game
  12.   programming under os/2.
  13.  
  14.   Do not expect a full documented full-blown 100% perfect code. This is just
  15.   an old dos game which i ported to os/2. But i hope this game can at least
  16.   be an example how to use multithreading and MMPM to write a game.
  17.  
  18.   If you want futher development, don't ask me. You have the source
  19.   code so you can do it ;-).
  20.  
  21.   Perhaps some time a new version of the game is released.
  22.  
  23.   What is still to do:
  24.     DIVE:    The new Fullscreen DIVE interface is not yet implemented.
  25.              Look for the file DIVEFS2.ZIP for docs.
  26.  
  27.     JOYSTICK:The game uses direct port io which ist not the best method.
  28.              Look for the files JOYSTICK.ZIP and JOYDOCS.ZIP for a OS/2
  29.              MMPM joystick driver.
  30.  
  31.     SOUND:   A playlist with alternatively updated datablocks and
  32.              cuepoint-operations is used. This takes much proc-time for
  33.              message processing etc. There is a new example for direct-
  34.              driver access. Look for DIRAUD.ZIP for documentation.
  35.  
  36.              The Sound-Part is only roughly tested and may not run
  37.              with some drivers. For the GUS it works with the Gravis drivers
  38.              but not with the manley-drivers. The Problem here is that
  39.              the driver is reading the playlist-buffer once and then is
  40.              ignoring any changes in the buffer.
  41.  
  42.     ERRORS:  Error processing is minimal or not-existing in this example.
  43.  
  44.  
  45.     To compile:
  46.  
  47.     Put the .LIB files in the LIB directory.
  48.     The .res and .rc have probably to stay in the output dirs.
  49.     The .def has to stay in the source-dir.
  50.  
  51.     Turn Stack-Checking off in the Compiler settings.
  52.     Link as PM-Application.
  53.  
  54.     The Compiler is: Virtual Pascal Version 1.0 Beta (#003)
  55.                      (i applied no fixes yet)
  56.                      from : Vitaly Miryanov
  57.  
  58.  
  59.     Used sources of information -> Credits:
  60.       SHOW.C of IBM for dive-programming.
  61.       The MM4EMX package of Marc E.E. van Woerkom for the MCI-Interface.
  62.       The plug-n-play sound source from Semir Patel.
  63.  
  64. ****************************************************************************)
  65.  
  66.  
  67. Program DiveRace;
  68.  
  69. {$S-}
  70. {$R-}
  71.  
  72.  
  73. uses Os2Def, Os2Base, Os2PmApi, Use32,Strings,Dive,DreiD,GfxFunc,SoundDrv;
  74.  
  75.  
  76. {$IFDEF DYNAMIC_VERSION}
  77.   {$Dynamic System }
  78.   {$L VPRTL.LIB}
  79. {$ENDIF}
  80.  
  81.  
  82.  
  83. (*Thread List:
  84.  
  85. Prio:       │Name:           │ Description:
  86. -----------------------------│--------------------------------------------
  87. Regular     │Main Thread     │ Message Processing for Dive Window
  88.             │                │
  89. Idle+10     │Blitter Thread  │ Setting up Graphics Buffer and Blit Buffer
  90.             │                │ to Screen
  91.             │                │
  92. Regular     │Game Thread     │ Game Control & Simulation
  93.             │                │
  94.             │                │
  95. Timecrit-2  │Sound Thread    │ Performing Sound Mixing.   (if enabled)
  96. Timecrit-1  │Timer Thread    │ Providing Timed Information
  97. Timecrit    │JoyStick Thread │ Checking Joystick Controls (if available)
  98.  
  99. *)
  100.  
  101.  
  102. (*Race Globals*)
  103.  
  104.  
  105.  
  106. const
  107.   ColOfs = 16;
  108.  
  109.   Black         = 0 +ColOfs;
  110.   Blue          = 1 +ColOfs;
  111.   Green         = 2 +ColOfs;
  112.   Cyan          = 3 +ColOfs;
  113.   Red           = 4 +ColOfs;
  114.   Magenta       = 5 +ColOfs;
  115.   Brown         = 6 +ColOfs;
  116.   LightGray     = 7 +ColOfs;
  117.   DarkGray      = 8 +ColOfs;
  118.   LightBlue     = 9 +ColOfs;
  119.   LightGreen    = 10+ColOfs;
  120.   LightCyan     = 11+ColOfs;
  121.   LightRed      = 12+ColOfs;
  122.   LightMagenta  = 13+ColOfs;
  123.   Yellow        = 14+ColOfs;
  124.   White         = 15+ColOfs;
  125.  
  126.   carcol : array[0..7] of byte = (White,Blue,Brown,Cyan,Red,Green,Magenta,Black);
  127.   maxpos = 200;
  128.   maxsub = 10;
  129.  
  130.   dirincmax = 40;
  131.   spincmax = 12;
  132.   dirincdiv = 2;
  133.   dirincinc = 6;
  134.   dirincdec = 8;
  135.  
  136.   linedist  = 1000;
  137.  
  138.  
  139.   zentmax1 = 3000; {Car Direction Centering "Force" on Street}
  140.   zentmax2 = 1000;(*1000*) {On Grass}
  141.   maxspeed = 600;
  142.  
  143.   carmaxsp = 600; {Maximum "Speed" for Computer Cars}
  144.   caracc   = 5;   {Car accelleration}
  145.  
  146.  
  147. var
  148.   ground : array[0..81,0..9] of byte; (*Ground-Matrix: Street or Grass*)
  149.  
  150.   KeyHeldDown : array[1..127] of boolean; (*Keyboard Scancode-Info *)
  151.  
  152.   dirinc,                 (*Direction-Change Value of user-controlled car*)
  153.   lastdirinc,             (*Dir-Change of previous sim-turn*)
  154.   keydirinc,              (*Keyboard Steering-Value*)
  155.   speed,                  (*Speed of User controlled car*)
  156.  
  157.   xrest,                  (*X-Move Remainder of User-Controlled Car*)
  158.   zrest,                  (*Z-Move Remainder of User-Controlled Car*)
  159.                           (*Remainders are kept for next Simulation Turn*)
  160.  
  161.   dx,                     (*X-Move*)
  162.   dz : longint;           (*Z-Move*)
  163.  
  164.   skid,lastskidded : boolean; (*Car Skidding, was Skidding ?*)
  165.  
  166.   zentri,zentmax,         (*Centering-"Force" of user-controlled car*)
  167.   preskid,                (*Before-Skid countdown*)
  168.  
  169.   dw: longint;            (*Turn-Angle change from last Sim-Turn*)
  170.  
  171.   godir,                  (*Direction where car actually moves*)
  172.                           (*godir<>y_angle when skidding*)
  173.   sp : integer;           (*Speed Increment*)
  174.  
  175.   y_angle : longint;      (*User Controlled car, Turn Angle*)
  176.   px,py,pz : longint;     (*Car-Position*)
  177.  
  178.   cars:carlist;           (*Data for cars in Game*)
  179.  
  180.   Timer : longint;        (*Counter of Timer-Events*)
  181.  
  182.   TimeStart,TimeStop,     (*Statistical Values*)
  183.   Frames,calcs:longint;
  184.  
  185.   xv,yv,zv,yw:integer;    (*Eye position and angle*)
  186.  
  187.   tarcsin : array[-100..100] of integer;
  188.  
  189.   (***************************************)
  190.   Laps,                   (*Display Stats*)
  191.   GameTime,
  192.   BestTime : integer;
  193.  
  194.   (***************************************)
  195.  
  196. type params = record
  197.                 Joystick,
  198.                 Sound,
  199.                 Test,
  200.                 Up,
  201.                 Wave,
  202.                 NoTrans,
  203.                 PauseNoFocus : boolean; (*Program Parameters*)
  204.                 Reserved : array[0..62] of byte;
  205.               end;
  206. var
  207.   parms : params;
  208.  
  209. (***************************************************************************)
  210.  
  211. Function GetCfgName:string;
  212. var cfgname:string;
  213. begin
  214.   cfgname:=paramstr(0);
  215.   if cfgname='' then
  216.     cfgname:='DIVERACE';
  217.   if pos('.',cfgname)<>0 then
  218.     cfgname:=copy(cfgname,1,pos('.',cfgname)-1);
  219.  
  220.   GetCfgName:=cfgname+'.CFG';
  221. end;
  222.  
  223.  
  224. Procedure GetParams;
  225. var
  226.   cfg:file of params;
  227. begin
  228.   Fillchar(parms,sizeof(params),FALSE);
  229.   parms.PauseNoFocus:=TRUE;
  230.   Assign(cfg,GetCfgName);
  231.   {$I-}Reset(cfg);{$I+}
  232.   If ioresult=0 then begin
  233.     Read(cfg,parms);
  234.     Close(cfg);
  235.   end;
  236. end;
  237.  
  238. Procedure WriteParams;
  239. var
  240.   cfg:file of params;
  241. begin
  242.   Assign(cfg,GetCfgName);
  243.   Rewrite(cfg);
  244.   If ioresult=0 then begin
  245.     Write(cfg,parms);
  246.     Close(cfg);
  247.   end;
  248. end;
  249.  
  250. (***************************************************************************)
  251.  
  252. (*Angle-Conversion Routines*)
  253. Function To360(x:longint):Longint;
  254. begin
  255.   x:=x mod 360;
  256.   if x>360 then dec(x,360)
  257.   else
  258.     if x<0 then inc(x,360);
  259.   To360:=x;
  260. end;
  261.  
  262. Function To180(x:longint):Longint;
  263. begin
  264.   x:=x mod 360;
  265.   if x>180 then dec(x,360)
  266.   else
  267.     if x<-180 then inc(x,360);
  268.   To180:=x;
  269. end;
  270.  
  271. (*Is Ground at y,x Street or Grass ?*)
  272. Function GroundOk(y,x:integer):boolean;
  273. begin
  274.   GroundOk:=Ground[x,y shr 3] and (1 shl (y and 7))=0;
  275. end;
  276.  
  277. (*Range-Check for values*)
  278. Function Range(x:Longint;min,max:Longint):Longint;
  279. begin
  280.   if x<min then x:=min
  281.     else if x>max then x:=max;
  282.   Range:=x;
  283. end;
  284.  
  285. (*Convert String To Upper Case*)
  286. Function Strupcase(s:string):string;
  287. var i:integer;
  288. begin
  289.   for i := 1 to Length(s) do
  290.     s[i] := UpCase(s[i]);
  291.   Strupcase:=s;
  292. end;
  293.  
  294. (*Find a Commandline Parameter*)
  295. Function FindParam(s:string):boolean;
  296. var i:integer;
  297. begin
  298.   s:=strupcase(s);
  299.   FindParam:=false;
  300.   for i:=1 to paramcount do
  301.     if pos(s,strupcase(paramstr(i)))<>0 then
  302.       FindParam:=true;
  303. end;
  304.  
  305. (*Inits ArcSin Array*)
  306. Procedure InitArcSin;
  307.  
  308. const
  309.   cpi=3.141592654;
  310.  
  311. var i,j:longint;
  312.     dt,dtalt:double;
  313.     adt,adtalt:double;
  314.  
  315.     sinarg,sinval:double;
  316.  
  317.  
  318. begin
  319.   i:=270;
  320.   j:=-100;
  321.   while j<=100 do
  322.   begin
  323.     dt:=sin(i*pi/180.0)-j/100;
  324.     repeat
  325.       inc(i);
  326.       if i=360 then i:=0;
  327.       dtalt:=dt;
  328.  
  329.       sinarg:=(i*cpi)/180.0;
  330.       sinval:=sin(sinarg);
  331.  
  332.       dt:=sin((i*cpi)/180.0)-j/100;
  333.  
  334.       adt:=abs(dt); (*compiler-error circumvent*)
  335.       adtalt:=abs(dtalt);
  336.  
  337.     until adt>adtalt;
  338.     dec(i);
  339.     if i<0 then inc(i,360);
  340.     tarcsin[j]:=i;
  341.     inc(j);
  342.   end;
  343. end;
  344.  
  345.  
  346. (***************************************************************************)
  347. (*Collision Check for cars*)
  348. Function CheckCol(var cars:carlist;var chx,chz,chsp:integer;chyw,notcheck:integer):boolean;
  349. const
  350. (*  coldist : array[0..18] of integer =
  351.              (50,60,70,75,65,55,45,40,35,30,35,40,45,55,65,75,70,60,50);*)
  352.   coldist : array[0..18] of integer =
  353.              (60,70,80,85,75,60,50,45,35,30,35,45,50,60,75,85,80,70,60);
  354. var
  355.   i,w,d,maxd:integer;
  356. begin
  357.   CheckCol:=false;
  358.     for i:=0 to cars.carnum do begin
  359.       if i<>notcheck then begin
  360.         with cars.carinfo[i] do
  361.         begin
  362.           d:=abs(cx-chx)+abs(cz-chz);
  363.           if d<180 then
  364.           begin
  365.             w:=GetAngle(cx-chx,cz-chz);
  366.             maxd:=coldist[abs(to180(w-chyw)) div 10]+
  367.                   coldist[abs(to180(w-180-cyw)) div 10];
  368.             if d<maxd then
  369.             begin
  370.               if(i=0) then
  371.                 PlayVoice(2);
  372.  
  373.               d:=maxd-d;
  374.               if abs(to180(w-chyw))<90 then {Stoß nach vorne ?}
  375.               begin
  376.                 CheckCol:=TRUE;
  377.                 if chsp>d then dec(chsp,d)
  378.                   else chsp:=0;
  379.               end;
  380.  
  381.               chx:=chx-((cx-chx)*(d+10)) div maxd;
  382.               chz:=chz-((cz-chz)*(d+10)) div maxd;
  383.             end;
  384.           end;
  385.         end;
  386.       end;
  387.     end;
  388. end;
  389.  
  390. (***************************************************************************)
  391. (*Sound of Computer-Controlled cars*)
  392. Procedure Carsound(var c:integer);
  393. const
  394. (*  volmax = 6;*)
  395.   VolMax = 100;
  396. var
  397.   dx,dz,dist,Vol,Volf,VolL,VolR,doppler:integer;
  398. begin
  399.   with cars.carinfo[c] do
  400.   begin
  401.     dx:=cx-px;             {Sound}
  402.     dz:=cz-pz;
  403.     dist:=abs(dx)+abs(dz);
  404.     doppler:=(lastdist-dist) div 10;
  405.     if abs(doppler)>50 then
  406.       if doppler<0 then doppler:=-50 else doppler:=50;
  407.     if Dist<1000 then
  408.     begin
  409.       Vol:=VolMax-((VolMax)*dist) div 1000;
  410.       Volf:=8000+((Carsp+doppler)*40000) div carmaxsp;
  411.       Volf:=Volf+((Volf*doppler) div 100);
  412.  
  413.       If Volf<1000 then Volf:=1000;
  414.       If Volf>80000 then Volf:=80000;
  415.  
  416.       SetVoiceRate(c+3,Volf);
  417.       SetVoiceVol(c+3,Vol,Vol);
  418.  
  419.       If not VoiceIsPlaying(c+3) then
  420.         PlayVoice(c+3);
  421.     end
  422.     else
  423.       If VoiceIsPlaying(c+3) then StopVoice(c+3);
  424.  
  425.     lastdist:=dist;
  426.   end;
  427. end;
  428.  
  429.  
  430. (***************************************************************************)
  431. (*Simulation Part for computer-controlled cars*)
  432. Procedure AutoCar;
  433.  
  434. var
  435.   k,c,dw,i:integer;
  436.   endit:boolean;
  437.  
  438.   Function Dirok(var c:carentry;w:integer):boolean;
  439.  
  440.   begin
  441.     with c do
  442.       Dirok:=groundok((cx+pisin(400,w)) div 100,
  443.                       (cz+picos(400,w)) div 100);
  444.  
  445.   end;
  446.  
  447. begin
  448.   with cars do
  449.   begin
  450.     for k:=1 to carnum do begin
  451.       c:=k;
  452.       with carinfo[c] do
  453.       begin
  454.         if not DirOk(carinfo[c],cyw) then
  455.         begin
  456.           dw:=0;
  457.           endit:=false;
  458.           repeat
  459.             inc(dw,5);
  460.             if DirOk(carinfo[c],To360(cyw-dw)) then
  461.             begin
  462.               cyw:=To360(cyw-dw);
  463.               endit:=true;
  464.             end
  465.             else
  466.               if  DirOk(carinfo[c],To360(cyw+dw)) then
  467.               begin
  468.                 cyw:=To360(cyw+dw);
  469.                 endit:=true;
  470.               end
  471.               else
  472.                 if dw>=5 then
  473.                 begin
  474.                   if carsp>70 then
  475.                     dec(carsp,20+random(30-(2*c)));
  476.                 end;
  477.           until endit;
  478.         end
  479.         else
  480.           if carsp<carmaxsp then
  481.             inc(carsp,caracc);
  482.         cz:=cz+longint(tcos[cyw])*carsp div 10000;
  483.         cx:=cx+longint(tsin[cyw])*carsp div 10000;
  484.         if not groundok(cx div 100,cz div 100) then
  485.           if carsp>carmaxsp shr 2 then
  486.              dec(carsp,spincmax);
  487.  
  488.  
  489.         if CheckCol(cars,integer(cx),integer(cz),carsp,cyw,c) then
  490.           if dirok(carinfo[c],to360(cyw-5)) then
  491.             cyw:=to360(cyw-5)
  492.           else
  493.           if dirok(carinfo[c],to360(cyw+5)) then
  494.             cyw:=to360(cyw+5);
  495.  
  496.         CarSound(c);
  497.       end;
  498.     end;
  499.   end;
  500. end;
  501.  
  502. (***************************************************************************)
  503. (*Read Ground-Info File*)
  504. Procedure GetGround;
  505. var
  506.   f:text;
  507.   s:string[100];
  508.   i,j : integer;
  509. begin
  510.   fillchar(ground,sizeof(ground),0);
  511.   assign(f,'COURSE1.TXT');
  512.   {$I-}reset(f);{$I+}
  513.   if ioresult<>0 then begin
  514.     WinMessageBox( HWND_DESKTOP, HWND_DESKTOP,
  515.        'File COURSE1.TXT not in current directory !!',
  516.        'Error!', 0, MB_OK or MB_MOVEABLE );
  517.     HALT;
  518.   end
  519.   else
  520.   begin
  521.     readln(f,s);
  522.     for i:=0 to 81 do
  523.     begin
  524.       readln(f,s);
  525.       s:=copy(s,3,82);
  526.       for j:=0 to 81 do
  527.         if s[j+1]<>' ' then
  528.           ground[i,j shr 3]:=ground[i,j shr 3] or (1 shl (j and 7));
  529.     end;
  530.     close(f);
  531.   end;
  532. end;
  533.  
  534. (***************************************************************************)
  535. (*Players Car Sound*)
  536.  
  537. Procedure DriveSound(x:longint);
  538. begin
  539.   x:=8000+(x*40000) div maxspeed;
  540.   SetVoiceRate(0,x);
  541. end;
  542.  
  543. (***************************************************************************)
  544. (*Car Simulation*)
  545. Procedure CarControl;
  546. begin
  547.   if not skid then
  548.     if speed<0 then
  549.     begin
  550.       if sp>0 then inc(speed,sp);
  551.     end
  552.     else
  553.       if (speed<maxspeed) or (sp<0) then
  554.       begin
  555.         inc(speed,sp);
  556.         if speed>maxspeed then speed:=maxspeed
  557.         else
  558.           if speed<0 then speed:=0;
  559.       end;
  560.  
  561.   DriveSound(Speed);
  562.   if speed<>0 then
  563.   begin
  564.     if groundok(px div 100,pz div 100) then
  565.     begin
  566.       zentmax:=zentmax1;
  567.      (* Mem[$a000:150*320+20]:=0;*)
  568.     end
  569.     else
  570.     begin
  571.       zentmax:=zentmax2;
  572.       (*Mem[$a000:150*320+20]:=9;*)
  573.       if speed>maxspeed div 2 then
  574.       begin
  575.         if sp>0 then dec(speed,sp);
  576.         if speed>maxspeed div 2 then
  577.           dec(speed,spincmax);
  578.       end;
  579. (*      if speed>maxspeed div 4 then
  580.       begin
  581.         if sp>0 then dec(speed,sp);
  582.         if speed>maxspeed div 4 then
  583.           dec(speed,spincmax);
  584.       end;*)
  585.     end;
  586.  
  587.     if not lastskidded then    {Eigentlich div 100 aber speed ist 10fach}
  588.       zentri:=(tsin[to360( dirinc*speed div  1000 )] * speed) div 10 {1000fach}
  589.     else
  590.       zentri:=(tsin[to360( y_angle+lastdirinc-godir)] * speed) div 10;
  591.  
  592.     skid:=false;
  593.     if abs(zentri)>zentmax then begin
  594.       if preskid<=0 then
  595.         skid:=true
  596.       else begin
  597.         dec(preskid,(abs(zentri)-zentmax) div 4);
  598.         If preskid>=0 then
  599.           SetVoiceVol(1,((zentmax-preskid)*100) div zentmax,
  600.                         ((zentmax-preskid)*100) div zentmax);
  601.         If not VoiceIsPlaying(1) then PlayVoice(1);
  602.       end;
  603.     end
  604.     else begin
  605.       If VoiceIsPlaying(1) then StopVoice(1);
  606.       preskid:=zentmax;
  607.     end;
  608.  
  609.     if not skid then (*No Skidding -> car drives in view direction*)
  610.     begin
  611.  
  612.       if lastskidded then
  613.         speed:=(tcos[to360(y_angle-godir)]*longint(speed)) div 1000;
  614.  
  615.       dx:=(tsin[to360(dirinc div 2 + y_angle)]*speed) div 10 + xrest;
  616.       dz:=(tcos[to360(dirinc div 2 + y_angle)]*speed) div 10 + zrest;
  617.       lastdirinc:=dirinc*speed div 1000;
  618.       y_angle:=to360(y_angle+lastdirinc);
  619.       godir:=y_angle;
  620.     end
  621.     else
  622.     begin
  623.       If not VoiceIsPlaying(1) then PlayVoice(1);
  624.  
  625.       dx:=(tsin[godir]*speed) div 10 + xrest;
  626.       dz:=(tcos[godir]*speed) div 10 + zrest;
  627.       y_angle:=to360(y_angle+lastdirinc);
  628.       dw:=to180(y_angle-godir);
  629.       if abs(dw)<90 then
  630.         if dw>0 then
  631.           godir:=to360(godir+(tcos[to360(dw)]*tarcsin[zentmax div speed]) div 1000)
  632.         else
  633.           godir:=to360(godir-(tcos[to360(dw)]*tarcsin[zentmax div speed]) div 1000);
  634.       if speed>0 then
  635.       begin
  636.         dec(speed,abs(dirincmax*tsin[to360(y_angle+lastdirinc-godir)]) div 1000);
  637.         if speed<0 then speed:=0;
  638.       end
  639.       else
  640.       begin
  641.         inc(speed,abs(dirincmax*tsin[to360(y_angle+lastdirinc-godir)]) div 1000);
  642.         if speed>0 then speed:=0;
  643.       end;
  644.     end;
  645.     lastskidded:=skid;
  646.     lastdirinc:=(lastdirinc*19) div 20;
  647.  
  648.     xrest:=dx mod 1000;
  649.     zrest:=dz mod 1000;
  650.     dx:=dx div 1000;
  651.     dz:=dz div 1000;
  652.   end
  653.   else
  654.   begin
  655.     dx:=0;
  656.     dz:=0;
  657.     xrest:=0;
  658.     zrest:=0;
  659.     skid:=false;
  660.     lastskidded:=false;
  661.     If VoiceIsPlaying(1) then StopVoice(1);
  662.   end;
  663. end;
  664.  
  665.  
  666. (***************************************************************************)
  667.  
  668. (* Other Game Globals *)
  669.  
  670.  
  671.  
  672. type
  673.   WinData = record
  674.     fVrnDisabled:Bool;       (* ????  Visual region enable/disable  *)
  675.     fChgSrcPalette:Bool;     (* Flag for change of source palette   *)
  676.     hwndFrame:HWND;          (* Frame window handle                 *)
  677.     hwndClient:HWND;         (* Client window handle                *)
  678.     hDive:HDIVE;             (* DIVE handle                         *)
  679.     ulnumColor:ULONG;        (* Number of colors in bitmaps         *)
  680.     ulWidth:ULONG;           (* Bitmap width in pels                *)
  681.     ulHeight:ULONG;          (* Bitmap Height in pels               *)
  682.     fccColorFormat:FOURCC;   (* Bitmap color format                 *)
  683.     ulSrcLineSizeBytes:ULONG;(* source linesize                     *)
  684.  end;
  685.  
  686.  p_WinData = ^WinData;
  687.  
  688.  t_rgbx = record
  689.             b,g,r,x:byte;
  690.           end;
  691.  
  692.  t_rgbxpal8 = array[0..255] of t_rgbx;
  693.  p_rgbxpal8 = ^t_rgbxpal8;
  694.  
  695. const
  696.  
  697. (*Window ID's*)
  698.  
  699.   ID_MAINWND=256;
  700.   ID_OPTIONS=257;
  701.   ID_SNAP   =258;
  702.   ID_SNAP2  =259;
  703.   ID_SNAPFULL=264;
  704.   ID_EXIT   =260;
  705.   ID_NEWTEXT=261;
  706.   ID_START  =262;
  707.   ID_PAUSE  =263;
  708.  
  709.   ID_STARTUPDLG=300;
  710.   ID_BITMAP =301;
  711.  
  712.   ID_SOUND  =320;
  713.   ID_MOUSE  =321;
  714.   ID_JOY    =322;
  715.   ID_TEST   =323;
  716.   ID_WAVE   =324;
  717.   ID_TRANS  =325;
  718.   ID_FOCUS  =326;
  719.  
  720.  
  721.   (*Source Color-Type definitions, LUT8 is good for 8-Bit Source-Images
  722.     it uses a color lookuptable.
  723.  
  724.     You can disable coltranslate, but this speeds only up if destination
  725.     is 1:1 and Display Depth is also 8-Bit
  726.  
  727.     Good Video drivers could make translation and sizing with hardware ;-)
  728.     Then its also useless to stop coltranslate
  729.     *)
  730.  
  731.  
  732.   FOURCC_LUT8 = ord('L')+(ord('U') shl 8)+(ord('T') shl 16)+(ord('8') shl 24);
  733.   FOURCC_R565 = ord('R')+(ord('5') shl 8)+(ord('6') shl 16)+(ord('5') shl 24);
  734.   FOURCC_BGR4 = ord('B')+(ord('G') shl 8)+(ord('R') shl 16)+(ord('4') shl 24);
  735.   FOURCC_SCRN = 0;
  736.  
  737.   WM_VRNDISABLED = $007E;
  738.   WM_VRNENABLED  = $007F;
  739.  
  740.  
  741.  
  742. var
  743.   h_ab:HAB;                                (* PM anchor block handle            *)
  744.   h_dc:HDC;                                (* Device Context*)
  745.   h_pal:HPAL;                              (* Game Palette Handle*)
  746.   ulImage:   ULONG;    (* Image buffer number from Dive    *)
  747.   pPalette:  Pointer;  (* Pointer to bitmap palette area    *)
  748.  
  749.   timerevent:hev; (*Timer-Event *)
  750.   BlitEvent:hev;  (*Blit Synchronization with Game Thread*)
  751.   SimDataAccess:hev; (*Mutex-Sem for Simulation Data Access*)
  752.  
  753.   win_Data:WINDATA;         (* window data                          *)
  754.  
  755.   screenx,screeny:Integer;               (* Screen Size*)
  756.  
  757.   MainWav:Integer; (*Number/Handle of Car-Sound Wave-Info*)
  758.   CrashWav:Integer;
  759.  
  760.  
  761. const
  762.   pszMyWindow:Pchar = 'MyWindow';         (* Window class name              *)
  763.   pszTitleText:Pchar = 'Dive-Drive !';    (* Title bar text                 *)
  764.   outputWinSize:string[80]='';
  765.  
  766.   ulToEnd:Ulong = 0;                     (* End Blitting-Thread             *)
  767.   PauseDisplay:Boolean = FALSE;          (* Indicator to Pause Game         *)
  768.   coltranslate:boolean = TRUE;           (* Translate 256 Colors for Dive ? *)
  769.  
  770.  
  771.  
  772. (***************************************************************************)
  773.  
  774. (*Integer to String*)
  775. Function Strint(x:longint):string;
  776. var s:string[20];
  777. begin
  778.   Str(x,s);
  779.   StrInt:=s;
  780. end;
  781.  
  782. (*Real to String*)
  783. Function StrReal(x:real;len,prec:integer):string;
  784. var s:string[20];
  785. begin
  786.   Str(x:len:prec,s);
  787.   StrReal:=s;
  788. end;
  789.  
  790. (***************************************************************************)
  791. var achTitle: array[0..255] of char;
  792. Procedure SetMainWindowTitle(s:string);
  793. begin
  794.   StrPCopy(@achTitle,s);
  795.   WinPostMsg ( win_Data.hwndFrame, WM_COMMAND,
  796.                ID_NEWTEXT, longint(@achTitle));
  797. end;
  798.  
  799. (***************************************************************************)
  800. Procedure ShowTime(x,y:longint;Time:longint;colf:byte);
  801. type
  802.   str2=string[2];
  803. var
  804.   min,sec,cent:longint;
  805.  
  806. begin
  807.   cent:=(Time*1000) div 182;
  808.   sec:=cent div 100;
  809.   cent:=cent mod 100;
  810.   min:=sec div 60;
  811.   sec:=sec mod 60;
  812.   OutStr( x , y ,Colf,chr(min div 10+ord('0'))+chr(min mod 10+ord('0'))+':'+
  813.                        chr(sec div 10+ord('0'))+chr(sec mod 10+ord('0'))+':'+
  814.                       chr(cent div 10+ord('0'))+chr(cent mod 10+ord('0')));
  815. end;
  816.  
  817. (***************************************************************************)
  818.  
  819.  
  820. const                     (*JoyStick Info Variables*)
  821.   stickmax:integer=5000;
  822.   joystick_found : boolean=FALSE;
  823.   game_running   : boolean=FALSE;
  824.  
  825. var
  826.   button,stick_x,stick_mx,stick_y,stick_my:integer;
  827.  
  828.  
  829. (*JoyStick Thread. Checks Periodically Joystick-Information*)
  830.  
  831. Procedure GetStickXY(param:ulong); (*Time_Crit*)
  832. var x,y,joyloop : word;
  833.     p : byte;
  834.  
  835. begin
  836.   repeat
  837.     x:=0;
  838.     y:=0;
  839.     Port[$201]:=0;
  840.     for joyloop:=1 to stickmax do
  841.     begin
  842.       p:=Port[$201];
  843.       Inc(x,p and 1);
  844.       Inc(y,p shr 1 and 1);
  845.     end;
  846.     stick_x:=x;
  847.     stick_y:=y;
  848.     Button:=(not (p shr 4)) and 3;
  849.  
  850.     if stickmax=5000 then begin (*calibrate*)
  851.       stick_mx:=x;
  852.       stick_my:=y;
  853.       stickmax:=x*2;
  854.       if y*2>stickmax then
  855.         stickmax:=y*2;
  856.       if (stickmax=5000) or (stickmax=0) then
  857.         exit;
  858.       joystick_found:=TRUE;
  859.     end;
  860.  
  861.  
  862.     DosSleep(55);
  863.   until ulToEnd<>0;
  864. end;
  865.  
  866.  
  867. (***************************************************************************)
  868. (*Provides Timed EventSem, and counts Timer variable*)
  869.  
  870. Procedure TimerThread(param:ulong); (*Should run at Time_Crit or foreground*)
  871. var rc:longint;
  872. begin
  873.   Timer:=0;
  874.   while ulToEnd=0 do begin
  875.     rc:=DosPostEventSem(TimerEvent);
  876.     if rc=6 then exit;
  877.     DosSleep(55);
  878.     if not PauseDisplay then
  879.       Inc(Timer);
  880.   end;
  881. end;
  882.  
  883. (***************************************************************************)
  884. (*Blitter Thread: Does 3D Calculations and Blits Picture Buffer to Screen*)
  885.  
  886. Procedure BlitterThread(param1:ulong); (*Should run at idle + 10 (to avoid pulse)*)
  887. var
  888.   pwinData:P_WINDATA;       (* pointer to window data                 *)
  889.   ulFirstTime:ULONG;
  890.  
  891.   ulScanLineBytes:ULONG;
  892.   ulScanLines:ULONG;
  893.   mousepos:pointl;
  894.   StartTimer:Longint;
  895.   i,j:Longint;
  896.  
  897.   rc,postcount:Longint;
  898.  
  899. begin
  900.   pwinData:=P_WINDATA(param1);
  901.   ulFirstTime:=0;
  902.   frames:=0;
  903.  
  904.   while not game_running do
  905.     DosSleep(50);
  906.  
  907.   StartTimer:=Timer;
  908.   While game_running and (ulToEnd=0) do begin
  909.     repeat
  910.       rc:=DosWaitEventSem(BlitEvent,500);  (*Synchronize with Game-Control Updates*)
  911.  
  912.       if rc=6 then exit;
  913.       DosResetEventSem(BlitEvent,postcount);
  914.     until (rc<>640) or (not game_running) or (ulToEnd<>0); (*640 = Timeout Error*)
  915.     if ( pwinData^.fChgSrcPalette ) or ( ulFirstTime=0 ) then begin
  916.        if coltranslate then
  917.          DiveSetSourcePalette ( pwinData^.hDive, 0,
  918.                                 pwinData^.ulnumColor,
  919.                                 pPalette );
  920.        ulFirstTime:=$FFFF;
  921.     end;
  922.  
  923.  
  924.     if DiveBeginImageBufferAccess ( pwinData^.hDive,
  925.                                     ulImage,
  926.                                     Pointer(DispBuffer),
  927.                                     ulScanLineBytes,
  928.                                     ulScanLines )<>0 then Exit;
  929.  
  930.     DosRequestMutexSem(SimDataAccess,1000);
  931.  
  932.     Display(xv,yv,zv,yw,cars);
  933.  
  934.     DosReleaseMutexSem(SimDataAccess);
  935.  
  936.  
  937.     WinQueryPointerPos(HWND_DESKTOP,mousepos);
  938.  
  939.     If not parms.Test then begin
  940.       OutStr(10,10,White,'LAP:');
  941.       OutStr(10+ 5*8,10,Red,chr(Laps div 10 + ord('0'))+chr(laps mod 10+ord('0')));
  942.  
  943.       OutStr(10+10*8,10,White,'TIME:');
  944.       ShowTime(10+16*8,10,GameTime,Red);
  945.  
  946.       if BestTime<>999999 then begin
  947.         OutStr(10+26*8,10,White,'BEST:');
  948.         ShowTime(10+32*8,10,BestTime,Red);
  949.       end;
  950.  
  951.       if (speed<=maxspeed) and (speed>0) then
  952.         for i:=2 to 8 do begin
  953.            FillChar(DispBuffer^[i*xpels],maxspeed div 2,Blue);
  954.            FillChar(DispBuffer^[i*xpels],speed div 2,LightGreen);
  955.         end;
  956.  
  957.     end;
  958.  
  959.     if joystick_found then begin
  960.       mousepos.y:=range( (((stick_my-stick_y)*(ymax div 2)) div stick_my)+
  961.                          (ymax div 2),0,ymax);
  962.       mousepos.x:=range( (((stick_x-stick_mx)*(xmax div 2)) div stick_mx)+
  963.                          (xmax div 2),0,xmax);
  964.     end
  965.     else begin
  966.       mousepos.x:=(mousepos.x*(xmax+1)) div screenx;
  967.       mousepos.y:=(mousepos.y*(ymax+1)) div screeny;
  968.     end;
  969.  
  970.     for i:=range(mousepos.x-10,0,xmax) to range(mousepos.x+10,0,xmax) do
  971.       DispBuffer^[(ymax-range(mousepos.y,0,ymax))*(xmax+1)+i]:=Red;
  972.     for i:=range(mousepos.y-10,0,ymax) to range(mousepos.y+10,0,ymax) do
  973.       DispBuffer^[(ymax-i)*(xmax+1)+range(mousepos.x,0,xmax)]:=Red;
  974.  
  975.     If parms.Wave then
  976.       ShowWave(DispBuffer^,Red,xmax,ymax);
  977.  
  978.     (*color bar*)
  979. {    for i:=16 to 32 do
  980.       for j:=0 to 4 do
  981.         FillChar(DispBuffer^[(xmax+1)*(((I-16)*5)+j)],50,i);}
  982.  
  983.     DispBuffer^[10*(xmax+1)+currentblock]:=White;
  984.  
  985.  
  986.     DiveEndImageBufferAccess ( pwinData^.hDive, ulImage );
  987.  
  988.  
  989.     DiveBlitImage ( pwinData^.hDive,
  990.                     ulImage,
  991.                     DIVE_BUFFER_SCREEN );
  992.  
  993.     inc(frames);
  994.                         (*Update Statistics when neccessary*)
  995.     if Timer-StartTimer>=40 then begin
  996.       SetMainWindowTitle(StrReal((frames*18)/(Timer-StartTimer),2,6)+' Fps');
  997.       frames:=0;
  998.       StartTimer:=Timer;
  999.     end;
  1000.   end;
  1001. end;
  1002.  
  1003. (***************************************************************************)
  1004. (*Simulation Thread for Watching Computer-Controlled Cars*)
  1005.  
  1006. Procedure Tester(parm1:Ulong); (*Regular prio*)
  1007. var
  1008.   c:char;
  1009.   k,i:integer;
  1010.   savetime,nowtime,lasttime:longint;
  1011.   sp,d:integer;
  1012.   first:boolean;
  1013.   lastyw:integer;
  1014.   postcount:integer;
  1015.   rc:longint;
  1016.   mousepos:pointl;
  1017.  
  1018.   vol:integer;
  1019.  
  1020. begin
  1021.  
  1022.   with cars do
  1023.   begin
  1024.     carnum:=7; (*7*)
  1025.     for i:=1 to carnum do begin
  1026.       k:=i;
  1027.       with carinfo[k] do
  1028.       begin
  1029.         cx:=4750-150*k;
  1030.         (*cx:=3700+150*k;*)
  1031.         if odd(i) then
  1032.           cz:=250
  1033.         else
  1034.           cz:=350;
  1035.         cyw:=90;
  1036.         carsp:=0;
  1037.         col1:=carcol[k];
  1038.       end;
  1039.       InitVoice(i+3,MainWav,5,TRUE);
  1040.     end;
  1041.   end;
  1042.  
  1043.   with wo do
  1044.   begin
  1045.     d:=0;
  1046.     sp:=0;
  1047.  
  1048.  
  1049.     xv:=5500;
  1050.     yv:=50;
  1051.     zv:=200;
  1052.     yw:=270;
  1053.     frames:=0;calcs:=0;
  1054.     Timer:=0;
  1055.     TimeStart:=Timer;
  1056.     c:=#0;
  1057.     game_running:=TRUE;
  1058.  
  1059.     rc:=DosResetEventSem(TimerEvent,postcount);
  1060.     postcount:=0;
  1061.  
  1062.     InitVoice(0,MainWav,1,TRUE);
  1063.     SetVoiceVol(0,100,100);
  1064.     SetVoiceRate(0,15000);
  1065. (*    PlayVoice(0);*)
  1066.  
  1067.     If parms.Sound then
  1068.       StartPlayBack;
  1069.  
  1070.     While ulToEnd=0 do begin
  1071.  
  1072.       Dec(PostCount);
  1073.       if PostCount<=0 then begin (*Wait only when all posts are worked out*)
  1074.         rc:=DosWaitEventSem(TimerEvent,200);
  1075.         if rc=6 then exit;
  1076.         DosResetEventSem(TimerEvent,postcount);
  1077.       end;
  1078.  
  1079.       DosRequestMutexSem(SimDataAccess,1000);
  1080.  
  1081.       inc(calcs);
  1082.       AutoCar;
  1083.  
  1084.       if joystick_found then
  1085.       begin
  1086.         sp:=(((stick_my-stick_y)*23) div stick_my)*3;
  1087.         d:=((stick_x-stick_mx)*10) div stick_mx;
  1088.         inc(xv,pisin(sp,yw));
  1089.         inc(zv,picos(sp,yw));
  1090.         yw:=to360(yw+d);
  1091.       end
  1092.       else begin
  1093.         WinQueryPointerPos(HWND_DESKTOP,mousepos);
  1094.  
  1095.         sp:=(mousepos.y*150) div screeny - 75;
  1096.  
  1097.         d:=(mousepos.x*32) div screenx - 16;
  1098.  
  1099.         yw:=to360(yw+d);
  1100.         inc(xv,pisin(sp,yw));
  1101.         inc(zv,picos(sp,yw));
  1102.       end;
  1103.  
  1104.       px:=xv;
  1105.       pz:=zv;
  1106.       DosReleaseMutexSem(SimDataAccess);
  1107.  
  1108.  
  1109.       DosPostEventSem(BlitEvent); (*Blitting would be useful now*)
  1110.  
  1111.       If PauseDisplay then begin
  1112.         While PauseDisplay Do
  1113.           DosSleep(100);
  1114.         DosResetEventSem(TimerEvent,Postcount);
  1115.         PostCount:=1;
  1116.       end;
  1117.     end;
  1118.     game_running:=FALSE;
  1119.     TimeStop:=Timer;
  1120.   end;
  1121. end;
  1122.  
  1123. (***************************************************************************)
  1124. (*Car-Steering*)
  1125.  
  1126. Procedure Steering;
  1127. var
  1128.   sx,sy,dirmax:integer;
  1129.   mousepos:pointl;
  1130.  
  1131.  
  1132. begin
  1133.   dirmax:=dirincmax div 4 +
  1134.           ((dirincmax - (dirincmax div 4))*(maxspeed-speed)) div maxspeed;
  1135.  
  1136.   if joystick_found then
  1137.   begin
  1138.     dirinc:=((stick_x-stick_mx)*dirmax) div stick_mx;
  1139.  
  1140.     if abs(stick_y-stick_my) > stick_my shr 2 then
  1141.       if stick_y-stick_my<0 then
  1142.         sp:=spincmax-(spincmax*speed) div (maxspeed+1)
  1143.       else
  1144.         sp:=-spincmax*2
  1145.     else sp:=-((spincmax*speed) div (maxspeed+1) div 2);
  1146.   end
  1147.   else begin
  1148.     WinQueryPointerPos(HWND_DESKTOP,mousepos);
  1149.  
  1150.     dirinc:=((mousepos.x-(screenx shr 1))*dirmax) div (screenx shr 1);
  1151.     if abs((screeny shr 1)-mousepos.y)>(screeny shr 4) then
  1152.       if (screeny shr 1)-mousepos.y<0 then
  1153.         sp:=spincmax-(spincmax*speed) div (maxspeed+1)
  1154.       else
  1155.         sp:=-spincmax*2
  1156.     else sp:=-((spincmax*speed) div (maxspeed+1) div 2);
  1157.   end;
  1158.  
  1159.   CarControl;
  1160. end;
  1161.  
  1162. (****************************************************************************)
  1163. (*Race Game Sim Thread*)
  1164.  
  1165. procedure RaceGame;
  1166. const
  1167.   cardx=230;
  1168.   cardy=115;
  1169.   speedx=10;
  1170.   speedy=120;
  1171.   speedw=100;
  1172.   dirx=10;
  1173.   diry=130;
  1174.   dirw=100;
  1175.  
  1176.   finx=4080;
  1177.   finz=300;
  1178.   checkx=3850;
  1179.   checkz=6500;
  1180.  
  1181. var
  1182.   c:char;
  1183.   NowTime,SaveTime,StartTime:longint;
  1184.   checked,dummy:boolean;
  1185.   dirold,i,subcnt : integer;
  1186.  
  1187.   rc,postcount:integer;
  1188.  
  1189.  
  1190. (*  Procedure ShowCarpos(on:boolean);
  1191.   var i,x,z:longint;
  1192.   begin
  1193.     with cars do
  1194.     begin
  1195.       for i:=0 to carnum do
  1196.         with carinfo[i] do
  1197.         begin
  1198.           x:=cx;
  1199.           z:=cz;
  1200.  
  1201.           if on then
  1202.             if i<>0 then
  1203.               SetPixel(cardx+81- x div 100,cardy+ z div 100,col1)
  1204.             else
  1205.               SetPixel(cardx+81- x div 100,cardy+ z div 100,15)
  1206.           else
  1207.             if groundok(x div 100,z div 100) then
  1208.               SetPixel(cardx+81- x div 100,cardy+ z div 100,0)
  1209.             else
  1210.               SetPixel(cardx+81- x div 100,cardy+ z div 100,5);
  1211.         end;
  1212.     end;
  1213.   end;*)
  1214.  
  1215.   Procedure CheckPos;
  1216.   var NowTime:Longint;
  1217.   begin
  1218.     NowTime:=Timer;
  1219.     GameTime:=NowTime-StartTime;
  1220.     if not checked then
  1221.       if(abs(checkx-px)+abs(checkz-pz))<1000 then checked:=TRUE;
  1222.     if checked then
  1223.       if (px>=finx) and (px<finx+300) and (pz<600) then
  1224.       begin
  1225.         inc(laps);
  1226.  
  1227.  
  1228.         if NowTime-StartTime<BestTime then
  1229.           BestTime:=NowTime-StartTime;
  1230.         StartTime:=NowTime;
  1231.         Checked:=False;
  1232.       end;
  1233.   end;
  1234.  
  1235.   Procedure SetCarinfo;
  1236.   begin
  1237.     with cars.carinfo[0] do
  1238.     begin
  1239.       cx:=px;
  1240.       cz:=pz;
  1241.       cyw:=y_angle;
  1242.       carsp:=speed;
  1243.     end;
  1244.   end;
  1245.  
  1246.  
  1247. begin
  1248.   px:=4000;
  1249.   py:=20;
  1250.   pz:=300;
  1251.   y_angle:=90;
  1252.   with cars do
  1253.   begin
  1254.     carnum:=6;
  1255.     for i:=1 to 6 do
  1256.       with carinfo[i] do
  1257.       begin
  1258.         cx:=3700+150*i;
  1259.         if odd(i) then cz:=250 else cz:=350;
  1260.         cyw:=90;
  1261.         carsp:=0;
  1262.         col1:=carcol[i];
  1263.         lastdist:=abs(cx-px)+abs(cz-pz);
  1264.  
  1265.         InitVoice(i+3,MainWav,5,TRUE);
  1266.       end;
  1267.   end;
  1268.   dx:=0;dz:=0;
  1269.   godir:=y_angle;
  1270.   Speed:=0;
  1271.   xrest:=0;
  1272.   zrest:=0;
  1273.   dirinc:=0;
  1274.   keydirinc:=0;
  1275.   lastdirinc:=0;
  1276.   preskid:=0;
  1277.   skid:=false;
  1278.   dirold:=0;
  1279.   lastskidded:=false;
  1280.  
  1281.   c:=#0;
  1282.   Frames:=0;
  1283.   calcs:=0;
  1284.  
  1285.   PlayVoice(0);
  1286.  
  1287.   Checked:=false;
  1288.  
  1289.  
  1290.   If parms.Sound then
  1291.     StartPlayBack;
  1292.  
  1293.   SaveTime:=Timer;
  1294.   Timer:=0;
  1295.   StartTime:=Timer;
  1296.   BestTime:=999999;
  1297.   GameTime:=0;
  1298.   laps:=0;
  1299.   TimeStart:=Timer;
  1300.  
  1301.   rc:=DosResetEventSem(TimerEvent,postcount);
  1302.   postcount:=0;
  1303.  
  1304.   game_running:=TRUE;
  1305.  
  1306.   While ulToEnd=0 do begin
  1307.     Inc(SoundWatchDog);
  1308.     Dec(PostCount);
  1309.     if PostCount<=0 then begin (*Wait only when all posts are worked out*)
  1310.       rc:=DosWaitEventSem(TimerEvent,200);
  1311.       if rc=6 then exit;
  1312.       DosResetEventSem(TimerEvent,postcount);
  1313.     end;
  1314.  
  1315.     DosRequestMutexSem(SimDataAccess,1000);
  1316.  
  1317.  
  1318.     dirold:=dirinc;
  1319.     Steering;
  1320.  
  1321.     AutoCar;
  1322.  
  1323.     px:=range(px+dx,0,8100);
  1324.     pz:=range(pz+dz,0,8100);
  1325.     Setcarinfo;
  1326.  
  1327.     xv:=px;
  1328.     yv:=py;
  1329.     zv:=pz;
  1330.     yw:=y_angle;
  1331.  
  1332.                      (*BANG at Collision*)
  1333.     if CheckCol(cars,px,pz,speed,y_angle,0) then
  1334.       PlayVoice(2);
  1335.  
  1336.     CheckPos;
  1337.     inc(calcs);
  1338.  
  1339.     DosReleaseMutexSem(SimDataAccess);
  1340.  
  1341.  
  1342.     DosPostEventSem(BlitEvent); (*Blitting would be useful now*)
  1343.  
  1344.     If PauseDisplay then begin
  1345.       While PauseDisplay Do
  1346.         DosSleep(100);
  1347.       DosResetEventSem(TimerEvent,Postcount);
  1348.       PostCount:=1;
  1349.     end;
  1350.   end;
  1351.   game_running:=FALSE;
  1352.   TimeStop:=Timer;
  1353. end;
  1354.  
  1355.  
  1356. (****************************************************************************)
  1357. (*Sets Up the Palette Array*)
  1358.  
  1359. Procedure SetPaletteArray(var pPalette:Pointer);
  1360. var
  1361.   i:longint;
  1362.   rgbxpal:p_rgbxpal8; (*Pointer to Palette*)
  1363.  
  1364. begin
  1365.   GetMem(pPalette,256*sizeof(ULONG));
  1366.  
  1367.   rgbxpal:=pPalette;
  1368.   FillChar(rgbxpal^,sizeof(rgbxpal^),#0);
  1369.  
  1370.   for i:=0 to 31 do  (*initialize Palette*)
  1371.     with rgbxpal^[i] do begin   (*Basic Colors*)
  1372.       b:=((i and 1)*8+(i and 8))*15;
  1373.       g:=((i and 2)*4+(i and 8))*15;
  1374.       r:=((i and 4)*2+(i and 8))*15;
  1375.       if i>15 then
  1376.         x:=PC_RESERVED
  1377.       else
  1378.         x:=0;
  1379.     end;
  1380.  
  1381.   for i:=0 to 49 do    (*Sky*)
  1382.     with rgbxpal^[i+100] do begin
  1383.       r:=((i*200) div 64);
  1384.       g:=(200+(i*40) div 64);
  1385.       b:=(200+(i*40) div 64);
  1386.       x:=PC_RESERVED;
  1387.     end;
  1388.   for i:=0 to 49 do    (*Ground*)
  1389.     with rgbxpal^[199-i] do begin
  1390.       r:=((i*40) div 64)    shl 2;
  1391.       g:=(40+(i*20) div 64) shl 2;
  1392.       b:=((i*40) div 64)    shl 2;
  1393.       x:=PC_RESERVED;
  1394.     end;
  1395. end;
  1396.  
  1397.  
  1398. (****************************************************************************)
  1399. (*Initializes Buffer allocated by DIVE APIs*)
  1400.  
  1401. Function AllocImgBuffer (var win_Data:WINDATA ):Ulong;
  1402. var
  1403.    ulNumBytes:ULONG;            (* output for number of bytes actually read *)
  1404.  
  1405.  
  1406.    pbBuffer:Pointer;            (* pointer to the image/ temp. palette data *)
  1407.  
  1408.    ulScanLineBytes:ULONG;       (* output for number of bytes a scan line   *)
  1409.    ulScanLines:ULONG;           (* output for height of the buffer          *)
  1410.  
  1411.    i,j:Longint;
  1412.  
  1413.    pbTmpDst:Pointer;            (* temporaly destination pointer            *)
  1414.    ulAllocX:Ulong;
  1415.  
  1416. const
  1417.   winx=xmax+1;
  1418.   winy=ymax+1;
  1419.   ColorBits=8; (*Allowed: 8,16,24*)
  1420.  
  1421. begin
  1422.   (* Set how many color bitmap data is supporting
  1423.   *)
  1424.   win_Data.ulnumColor:=1 shl ColorBits;
  1425.  
  1426.   (* Set bitmap width and height in pels.
  1427.   *)
  1428.   win_Data.ulWidth  := Winx;
  1429.   win_Data.ulHeight := Winy;
  1430.  
  1431.   (* Calculate source line size.  It should be double word boundary.
  1432.   *)
  1433.   win_Data.ulSrcLineSizeBytes := (((WinX* (ColorBits shr 3))+3) div 4)*4;
  1434.  
  1435.   (* Adjust the width in pixels for memory to allocate.
  1436.     *)
  1437.   ulAllocX := Winx*(ColorBits shr 3);
  1438.   while ulAllocX < win_Data.ulSrcLineSizeBytes do
  1439.     Inc(ulAllocX,ColorBits shr 3);
  1440.  
  1441.   (* Set bitmap coclor format.
  1442.    *)
  1443.   case ColorBits of
  1444.     8: win_Data.FccColorFormat:=FOURCC_LUT8;
  1445.    16: win_Data.FccColorFormat:=FOURCC_R565;
  1446.    24: win_Data.FccColorFormat:=FOURCC_BGR4;
  1447.   end;
  1448.  
  1449.    (* Allocate a buffer for image data
  1450.    *)
  1451.  
  1452.    if DiveAllocImageBuffer ( win_Data.hDive,
  1453.                              ulImage,
  1454.                              win_Data.fccColorFormat,
  1455.                              ulAllocX,
  1456.                              win_Data.ulHeight,
  1457.                              win_Data.ulSrcLineSizeBytes,
  1458.                              nil )<>0 then begin
  1459.       AllocImgBuffer:=1;
  1460.       exit;
  1461.    end;
  1462.  
  1463.    if DiveBeginImageBufferAccess ( win_Data.hDive,
  1464.                                      ulImage,
  1465.                                      pbBuffer,
  1466.                                      ulScanLineBytes,
  1467.                                      ulScanLines )<>0 then begin
  1468.       DiveFreeImageBuffer ( win_Data.hDive, ulImage );
  1469.       AllocImgBuffer:=1;
  1470.       exit;
  1471.    end;
  1472.  
  1473.    (* Init image Data-Buffer to 0 *)
  1474.    Fillchar(pbBuffer^,win_Data.ulWidth*win_Data.ulHeight,0);
  1475.  
  1476.    (* release the access to the image buffer *)
  1477.  
  1478.    DiveEndImageBufferAccess ( win_Data.hDive, ulImage );
  1479.  
  1480.    AllocImgBuffer:=0;
  1481. end;
  1482.  
  1483. (***************************************************************************
  1484.  * GetSnapHeight and -Width calculate the Height & Width of a Std-Window
  1485.  * with Menu for a target size of the client area
  1486.  ****************************************************************************)
  1487.  
  1488. Function GetSnapHeight(ulHeight:ULONG):ULONG;
  1489. begin
  1490.   Inc(ulHeight,
  1491.            WinQuerySysValue ( HWND_DESKTOP, SV_CYSIZEBORDER ) * 2);
  1492.   Inc(ulHeight,
  1493.            WinQuerySysValue ( HWND_DESKTOP, SV_CYBORDER ) * 2);
  1494.   Inc(ulHeight,
  1495.            WinQuerySysValue ( HWND_DESKTOP, SV_CYMENU ));
  1496.   Inc(ulHeight,
  1497.            WinQuerySysValue ( HWND_DESKTOP, SV_CYTITLEBAR ));
  1498.   GetSnapHeight:=ulHeight;
  1499. end;
  1500.  
  1501. Function GetSnapWidth(ulWidth:ULONG):ULONG;
  1502. begin
  1503.   Inc(ulWidth,
  1504.            WinQuerySysValue ( HWND_DESKTOP, SV_CXSIZEBORDER ) * 2);
  1505.   GetSnapWidth:=ulWidth;
  1506. end;
  1507.  
  1508.  
  1509. (*****************************************************************************)
  1510. (*Window Procedure of Startup Dialogue *)
  1511.  
  1512. function StartupDlgProc(Window: HWnd; Msg: ULong; Mp1,Mp2: MParam): MResult;cdecl;
  1513. var
  1514.   swpos       :SWP;                  (* Window position                      *)
  1515. begin
  1516.   case msg of
  1517.     WM_INITDLG:
  1518.       begin
  1519.         GetParams;
  1520.  
  1521.         WinSendDlgItemMsg(Window,ID_SOUND,BM_SETCHECK,longint(parms.Sound),0);
  1522.         If parms.Joystick then
  1523.           WinSendDlgItemMsg(Window,ID_JOY,BM_SETCHECK,1,0)
  1524.         else
  1525.           WinSendDlgItemMsg(Window,ID_MOUSE,BM_SETCHECK,1,0);
  1526.         WinSendDlgItemMsg(Window,ID_TEST,BM_SETCHECK,longint(parms.Test),0);
  1527.         WinSendDlgItemMsg(Window,ID_WAVE,BM_SETCHECK,longint(parms.Wave),0);
  1528.         WinSendDlgItemMsg(Window,ID_TRANS,BM_SETCHECK,longint(not parms.NoTrans),0);
  1529.         WinSendDlgItemMsg(Window,ID_FOCUS,BM_SETCHECK,longint(parms.PauseNoFocus),0);
  1530.  
  1531.         WinQueryWindowPos (Window , swpos );
  1532.  
  1533.         WinSetWindowPos ( Window, HWND_TOP,
  1534.                           (screenx div 2) - (swpos.cx div 2),
  1535.                           (screeny div 2) - (swpos.cy div 2),
  1536.                                     0,
  1537.                                     0,
  1538.                                     SWP_MOVE or SWP_ACTIVATE or SWP_SHOW );
  1539.  
  1540.  
  1541.       end; (*SetSysMenu(Window);*)
  1542.     WM_COMMAND:
  1543.       begin
  1544.         case USHORT(mp1) of
  1545.           DID_OK:
  1546.             begin
  1547.               parms.Sound:=Boolean(WinSendDlgItemMsg(Window,ID_SOUND,BM_QUERYCHECK,0,0));
  1548.               parms.Joystick:=Boolean(WinSendDlgItemMsg(Window,ID_JOY,BM_QUERYCHECK,0,0));
  1549.               parms.Test:=Boolean(WinSendDlgItemMsg(Window,ID_TEST,BM_QUERYCHECK,0,0));
  1550.               parms.Wave:=Boolean(WinSendDlgItemMsg(Window,ID_WAVE,BM_QUERYCHECK,0,0));
  1551.               parms.NoTrans:= not Boolean(WinSendDlgItemMsg(Window,ID_TRANS,BM_QUERYCHECK,0,0));
  1552.               parms.PauseNoFocus:=Boolean(WinSendDlgItemMsg(Window,ID_FOCUS,BM_QUERYCHECK,0,0));
  1553.               WriteParams;
  1554.               WinDismissDlg(Window, 1);
  1555.             end;
  1556.           DID_CANCEL:
  1557.               WinDismissDlg(Window, 0);
  1558.           else
  1559.             WinDismissDlg(Window, 0);
  1560.         end;
  1561.       end;
  1562.     else begin
  1563.       (* Let PM handle this message.
  1564.       *)
  1565.       StartupDlgProc:=WinDefDlgProc ( Window, msg, mp1, mp2 );
  1566.       exit;
  1567.     end;
  1568.   end;
  1569.   StartupDlgProc:=0;
  1570. end;
  1571.  
  1572. (*****************************************************************************)
  1573. (*Window Procedure of Dive-Window *)
  1574.  
  1575.  
  1576. function MyWindowProc(Window: HWnd; Msg: ULong; Mp1,Mp2: MParam): MResult;cdecl;
  1577. var
  1578.   point_l     :POINTL;               (* Point to offset from Desktop         *)
  1579.   swpos       :SWP;                  (* Window position                      *)
  1580.   h_rgn       :HRGN;                 (* Region handle                        *)
  1581.   h_ps        :HPS;                  (* Presentation Space handle            *)
  1582.   h_psPal     :HPS;                  (* Presentation Space handle            *)
  1583.   rcls        :array[0..49] of RECTL;(* Rectangle coordinates                *)
  1584.   rgnCtl      :RGNRECT;              (* Processing control structure         *)
  1585.   pwin_data    :P_WINDATA;            (* Pointer to window data               *)
  1586.   SetupBlitter:SETUP_BLITTER;        (* structure for DiveSetupBlitter       *)
  1587.   pPal        :PLONG;
  1588.  
  1589.   NoRectl     :PRECTL;
  1590.   PaletteColors:ULONG;
  1591.  
  1592.   sizl:SIZEL;
  1593.  
  1594.   rc:Ulong;
  1595.  
  1596. begin
  1597.   NoRectl:=Nil;
  1598.   pwin_data := P_WINDATA(WinQueryWindowULong (Window, 0));
  1599.   if ( pwin_data<>nil) or (msg=WM_CREATE) then begin
  1600.     case msg of
  1601.       WM_CREATE:
  1602.         begin
  1603.           (*Set Up Physical Palette*)
  1604.           sizl.cx:=0;
  1605.           sizl.cy:=0;
  1606.           h_dc:=WinOpenWindowDC(Window);
  1607.           h_psPal:=GpiCreatePS(h_ab,h_dc,sizl,
  1608.                             PU_PELS or GPIF_DEFAULT or GPIT_MICRO or GPIA_ASSOC);
  1609.  
  1610.           h_pal:=GpiCreatePalette(h_ab,LCOL_PURECOLOR (*or LCOL_OVERRIDE_DEFAULT_COLORS*), LCOLF_CONSECRGB,
  1611.                                   200,
  1612.                                   ULONG(pPalette^));
  1613.           rc:=GpiSelectPalette(h_psPal,h_pal);
  1614.  
  1615.           WinRealizePalette(Window,h_psPal,PaletteColors);
  1616.         end;
  1617.       WM_COMMAND:
  1618.         case USHORT(mp1) of
  1619.           ID_SNAP:
  1620.             begin  (*Snap Window to Dive Buffer Size*)
  1621.               WinSetWindowPos ( pwin_data^.hwndFrame, HWND_TOP,
  1622.                                     100, 100,
  1623.                                     GetSnapWidth(pwin_data^.ulWidth),
  1624.                                     GetSnapHeight(pwin_data^.ulHeight),
  1625.                                     SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
  1626.             end;
  1627.           ID_SNAP2:
  1628.             begin (*Snap Window to Size & height * 2*)
  1629.               WinSetWindowPos ( pwin_data^.hwndFrame, HWND_TOP,
  1630.                                     100, 100,
  1631.                                     GetSnapWidth(pwin_data^.ulWidth*2),
  1632.                                     GetSnapHeight(pwin_data^.ulHeight*2),
  1633.                                     SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
  1634.             end;
  1635.           ID_SNAPFULL:
  1636.             begin
  1637.               (*Snap to Full Size but retain (approx) aspect ratio*)
  1638.  
  1639.               WinSetWindowPos ( pwin_data^.hwndFrame, HWND_TOP,
  1640.                             0, screeny div 2-
  1641.                             ((pwin_data^.ulHeight*screenx) div pwin_data^.ulWidth) div 2,
  1642.                             screenx,
  1643.                             (pwin_data^.ulHeight*screenx) div pwin_data^.ulWidth,
  1644.                             SWP_MOVE or SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
  1645.             end;
  1646.           ID_EXIT:
  1647.             (* Post to quit the dispatch message loop.
  1648.              *)
  1649.             WinPostMsg ( Window, WM_QUIT, 0, 0 );
  1650.           ID_PAUSE:
  1651.             begin
  1652.               PauseDisplay:=not PauseDisplay;
  1653.               If PauseDisplay then begin
  1654.                 SetMainWindowTitle('Game PAUSED');
  1655.                 PausePlayBack;
  1656.               end
  1657.               else begin
  1658.                 SetMainWindowTitle('Game resumed');
  1659.                 ResumePlayBack;
  1660.               end;
  1661.             end;
  1662.           ID_NEWTEXT:
  1663.             (* Write new text string to the title bar
  1664.              *)
  1665.             WinSetWindowText ( pwin_data^.hwndFrame, PCHAR(mp2));
  1666.           else
  1667.             (* Let PM handle this message.
  1668.              *)
  1669.             MyWindowProc:=WinDefWindowProc ( Window, msg, mp1, mp2 );
  1670.             exit;
  1671.         end;
  1672.       WM_VRNDISABLED:
  1673.         DiveSetupBlitter ( pwin_data^.hDive, nil );
  1674.       WM_VRNENABLED:
  1675.         begin
  1676.           h_ps := WinGetPS ( Window );
  1677.           if h_ps<>0 then begin
  1678.             h_rgn := GpiCreateRegion ( h_ps, 0, NoRectl^ );
  1679.             if h_rgn<>0 then begin
  1680.               (* NOTE: If mp1 is zero, then this was just a move message.
  1681.               ** Illustrate the visible region on a WM_VRNENABLE.
  1682.               *)
  1683.               (*WinQueryUpdateRegion  (Window,h_rgn);*)
  1684.               WinQueryVisibleRegion ( Window, h_rgn );
  1685.               rgnCtl.ircStart     := 0;
  1686.               rgnCtl.crc          := 50;
  1687.               rgnCtl.ulDirection  := 1;
  1688.  
  1689.               (* Get the all ORed rectangles
  1690.               *)
  1691.               if GpiQueryRegionRects ( h_ps, h_rgn, NoRectl^, rgnCtl, rcls[0]) then
  1692.               begin
  1693.                 (* Now find the window position and size, relative to parent.
  1694.                 *)
  1695.                 WinQueryWindowPos ( pwin_data^.hwndClient, swpos );
  1696.  
  1697.                 (* Convert the point to offset from desktop lower left.
  1698.                 *)
  1699.                 point_l.x := swpos.x;
  1700.                 point_l.y := swpos.y;
  1701.                 WinMapWindowPoints ( pwin_data^.hwndFrame,
  1702.                                      HWND_DESKTOP, point_l, 1 );
  1703.  
  1704.                 (* Tell DIVE about the new settings.
  1705.                 *)
  1706.                 SetupBlitter.ulStructLen := sizeof ( SETUP_BLITTER );
  1707.                 SetupBlitter.fccSrcColorFormat := pwin_data^.fccColorFormat;
  1708.                 SetupBlitter.ulSrcWidth := pwin_data^.ulWidth;
  1709.                 SetupBlitter.ulSrcHeight := pwin_data^.ulHeight(* shr 1*);
  1710.                 SetupBlitter.ulSrcPosX := 0;
  1711.                 SetupBlitter.ulSrcPosY := 0;
  1712.                 SetupBlitter.fInvert := FALSE (*TRUE*);
  1713.                 SetupBlitter.ulDitherType := 0;
  1714.  
  1715.                 if coltranslate then
  1716.                   SetupBlitter.fccDstColorFormat := FOURCC_SCRN
  1717.                 else
  1718.                   SetupBlitter.fccDstColorFormat := FOURCC_LUT8;
  1719.  
  1720.                 SetupBlitter.ulDstWidth := swpos.cx;
  1721.                 SetupBlitter.ulDstHeight := swpos.cy(*shr 1*);
  1722.  
  1723.                 OutputWinSize:=' x:'+StrInt(SwPos.cx)+' y:'+Strint(SwPos.cy);
  1724.  
  1725.                 SetupBlitter.lDstPosX := 0;
  1726.                 SetupBlitter.lDstPosY := 0;
  1727.                 SetupBlitter.lScreenPosX := point_l.x;
  1728.                 SetupBlitter.lScreenPosY := point_l.y;
  1729.                 SetupBlitter.ulNumDstRects := rgnCtl.crcReturned;
  1730.                 SetupBlitter.pVisDstRects := @rcls;
  1731.                 rc:=DiveSetupBlitter ( pwin_data^.hDive, @SetupBlitter );
  1732.               end
  1733.               else
  1734.                 DiveSetupBlitter ( pwin_data^.hDive, nil );
  1735.  
  1736.               GpiDestroyRegion( h_ps, h_rgn );
  1737.             end;
  1738.            (* WinReleasePS( h_ps );*)
  1739.           end;
  1740.         end;
  1741.       WM_CHAR:
  1742.         begin
  1743.           (* Character input: first two byte of message is the character code.
  1744.           *)
  1745.           if (CharMsgMp1(Mp1).fs and kc_KeyUp) = 0 then { Key is Down }
  1746.             if USHORT(mp2 shr 16) = VK_F3 then
  1747.               WinPostMsg ( Window, WM_QUIT, 0, 0 )
  1748.             else
  1749.               if USHORT(mp2 shr 16) = VK_F1 then
  1750.                  WinPostMsg ( Window, WM_COMMAND, ID_SNAP, 0 )
  1751.               else
  1752.                 if USHORT(mp2 shr 16) = VK_F2 then
  1753.                    WinPostMsg ( Window, WM_COMMAND, ID_SNAP2, 0 )
  1754.                 else
  1755.                   if USHORT(mp2 shr 16) = VK_F4 then
  1756.                      WinPostMsg ( Window, WM_COMMAND, ID_SNAPFULL, 0 )
  1757.                   else
  1758.                     if USHORT(mp2 shr 16) = VK_F5 then
  1759.                        WinPostMsg ( Window, WM_COMMAND, ID_PAUSE, 0 )
  1760.                     else
  1761.                       if USHORT(mp2 shr 16) = VK_F10 then
  1762.                          WinPostMsg ( Window, WM_COMMAND, ID_START, 0 );
  1763.         end;
  1764.       WM_FOCUSCHANGE:
  1765.         if parms.PauseNoFocus then
  1766.           if(mp2 and 1)=1 then begin
  1767.             PauseDisplay:=FALSE;
  1768.             ResumePlayback;
  1769.             SetMainWindowTitle('Game resumed');
  1770.           end
  1771.           else begin
  1772.             SetMainWindowTitle('Game PAUSED ');
  1773.             PauseDisplay:=TRUE;
  1774.             PausePlayback; (*Pause Playback if window loses focus*)
  1775.           end;
  1776.       WM_REALIZEPALETTE:
  1777.         begin
  1778.           h_ps := WinBeginPaint ( pwin_data^.hwndFrame, 0 , Nil);
  1779.  
  1780.           GetMem(pPal,sizeof(LONG) * pwin_data^.ulnumColor);
  1781.  
  1782.           GpiQueryRealColors ( h_ps, 0, 0, pwin_data^.ulnumColor, pPal^ );
  1783.  
  1784.           if coltranslate then
  1785.             DiveSetDestinationPalette ( pwin_data^.hDive, 0,
  1786.                                         pwin_data^.ulnumColor,
  1787.                                         PBYTE(pPal));
  1788.           FreeMem(pPal,sizeof(LONG) * pwin_data^.ulnumColor);
  1789.  
  1790.           WinEndPaint ( h_ps );
  1791.          end;
  1792.       WM_CLOSE:
  1793.       begin
  1794.         (* Post to quit the dispatch message loop.
  1795.         *)
  1796.         GpiSelectPalette(h_psPal,0);
  1797.         GpiDeletePalette(h_pal);
  1798.         GpiDestroyPS(h_psPal);
  1799.  
  1800.         WinPostMsg ( Window, WM_QUIT, 0, 0 );
  1801.       end;
  1802.       else
  1803.         begin
  1804.           (* Let PM handle this message.
  1805.           *)
  1806.           MyWindowProc:=WinDefWindowProc ( Window, msg, mp1, mp2 );
  1807.           exit;
  1808.         end;
  1809.     end;
  1810.   end
  1811.   else begin
  1812.     (* Let PM handle this message.
  1813.     *)
  1814.     MyWindowProc:=WinDefWindowProc ( Window, msg, mp1, mp2 );
  1815.     exit;
  1816.   end;
  1817.   MyWindowProc:=0;
  1818. end;
  1819.  
  1820.  
  1821.  
  1822.  
  1823. (****************************************************************************)
  1824. (* Main Program *)
  1825.  
  1826. var
  1827.   tidBlitThread:TID;         (*Thread ID for Blitter Thread*)
  1828.   tidGame:TID;               (*Thread ID for Game-Control Thread*)
  1829.   tidTimer:TID;              (*Thread ID for Timer Thread*)
  1830.   tidStickXy:TID;            (*Thread ID for Joystick Thread*)
  1831.  
  1832.   h_mq:HMQ;                  (* Message queue handle                 *)
  1833.   q_msg:QMSG;                (* Message from message queue           *)
  1834.  
  1835.   h_ps:HPS;   (*Paint Section ??*)
  1836.  
  1837.   flCreate:ULONG;           (* Window creation control flags        *)
  1838.   i:ULONG;                  (* Index for Buffers to init            *)
  1839.   pPal:PLONG;               (* Pointer to system physical palette   *)
  1840.  
  1841.   rc:ULONG;
  1842.  
  1843.   NullPtr:Pointer;
  1844.  
  1845.   WinPosx,WinPosy:integer;
  1846.  
  1847.   hwndDlg:HWND;
  1848.  
  1849. begin
  1850.   (* Initialize the presentation manager, and create a message queue.
  1851.   *)
  1852.   h_ab := WinInitialize ( 0 );
  1853.   h_mq := WinCreateMsgQueue ( h_ab, 0 );
  1854.  
  1855.   InitDreiD;
  1856.  
  1857.   InitArcSin;
  1858.  
  1859. (*  Parm_JoyStick:=FindParam('JOY') or FindParam('JOYSTICK');
  1860.   Parm_Sound:=FindParam('SOUND');
  1861.   Parm_Test:=FindParam('TEST');
  1862.   Parm_Up:=FindParam('UP');
  1863.   Parm_Wave:=FindParam('WAVE');
  1864.   Parm_NoTrans:=FindParam('NOTRANS');*)
  1865.  
  1866.  
  1867. (*Init Race Vars*)
  1868.   Fillchar(cars,sizeof(cars),#0);
  1869.  
  1870.   GetGround;
  1871.   linemode:=FALSE;
  1872.  
  1873.  
  1874.  
  1875.   SetPaletteArray(pPalette);
  1876.  
  1877.   (*Get Screensize*)
  1878.   Screenx:=WinQuerySysValue ( HWND_DESKTOP, SV_CXSCREEN);
  1879.   Screeny:=WinQuerySysValue ( HWND_DESKTOP, SV_CYSCREEN);
  1880.  
  1881.   (*Create Window + Class *)
  1882.   WinRegisterClass ( h_ab, pszMyWindow, MyWindowProc, 0, sizeof(ULONG) );
  1883.  
  1884.   flCreate:=FCF_TASKLIST or FCF_SYSMENU or FCF_TITLEBAR or
  1885.                   FCF_SIZEBORDER or FCF_MINMAX or FCF_MENU or FCF_SCREENALIGN(*or FCF_SHELLPOSITION*);
  1886.  
  1887.   win_Data.hwndFrame:=WinCreateStdWindow ( HWND_DESKTOP,
  1888.                                            WS_VISIBLE, flCreate,
  1889.                                            pszMyWindow,
  1890.                                            pszTitleText,
  1891.                                            WS_SYNCPAINT or WS_VISIBLE,
  1892.                                            0, ID_MAINWND,
  1893.                                            win_Data.hwndClient);
  1894.  
  1895.   if WinDlgBox( HWND_DESKTOP,
  1896.              win_Data.hwndFrame,
  1897.              StartupDlgProc,
  1898.              0,
  1899.              ID_STARTUPDLG,
  1900.              Nil)=0 then begin
  1901.     WinDestroyMsgQueue ( h_mq );
  1902.     WinTerminate ( h_ab );
  1903.     Halt(0);
  1904.   end;
  1905.  
  1906.   coltranslate:=not parms.NoTrans;
  1907.  
  1908.   NullPtr:=Nil;
  1909.  
  1910.   (* Get a linear address to the screen.
  1911.   *)
  1912.   rc:=DiveOpen ( win_Data.hDive, FALSE, NullPtr );
  1913.   if rc<>0 then begin
  1914.     WinMessageBox( HWND_DESKTOP, HWND_DESKTOP,
  1915.        'Dive Open Error!',
  1916.        'Error!', 0, MB_OK or MB_MOVEABLE );
  1917.     WinDestroyMsgQueue ( h_mq );
  1918.     WinTerminate ( h_ab );
  1919.     Halt(1);
  1920.   end;
  1921.  
  1922.   (*Start Joystick-Thread*)
  1923.   If parms.Joystick then begin
  1924.     DosCreateThread(tidStickXY,@GetStickXY,0,0,8192);
  1925.  
  1926.     DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL,
  1927.                         0, tidStickXY );
  1928.     DosSleep(500);
  1929.   end;
  1930.  
  1931.  
  1932.  
  1933.   (* Initialize Buffers
  1934.   *)
  1935.   if AllocImgBuffer (win_Data )<>0 then begin
  1936.      WinMessageBox( HWND_DESKTOP, HWND_DESKTOP,
  1937.                     'Failed to initialize Frame Buffers.',
  1938.                     'Error!', 0, MB_OK or MB_MOVEABLE );
  1939.      WinDestroyMsgQueue ( h_mq );
  1940.      WinTerminate ( h_ab );
  1941.      Halt(1);
  1942.   end;
  1943.  
  1944.  
  1945.   WinSetWindowULong (win_Data.hwndClient, 0, ULONG(@win_Data));
  1946.  
  1947.  
  1948.   WinPosX:=ScreenX div 2 - (GetSnapWidth(win_Data.ulWidth) div 2);
  1949.   WinPosY:=ScreenY div 2 - (GetSnapHeight(win_Data.ulHeight) div 2);
  1950. (*  If parms.Up then
  1951.     WinPosY:=400;*)
  1952.  
  1953.   (* Set the size of the window *)
  1954.   WinSetWindowPos ( win_data.hwndFrame, HWND_TOP,
  1955.                                     WinPosX, WinPosY,
  1956.                                     GetSnapWidth(win_Data.ulWidth),
  1957.                                     GetSnapHeight(win_Data.ulHeight),
  1958.                                     SWP_MOVE or SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
  1959.  
  1960.  
  1961. (*  WinPostMsg ( win_Data.hwndClient, WM_COMMAND, ID_SNAP, 0 );*)
  1962.  
  1963.   (* Turn on visible region notification.
  1964.   *)
  1965.  
  1966.   WinSetVisibleRegionNotify ( win_Data.hwndClient, TRUE );  (*!!!!*)
  1967.  
  1968.  
  1969.   (* set the flag for the first time simulation of palette of bitmap data
  1970.   *)
  1971.   win_Data.fChgSrcPalette := FALSE;
  1972.  
  1973.   (* Send an invalidation message to the client.
  1974.   *)
  1975.   WinPostMsg ( win_Data.hwndFrame, WM_VRNENABLED, 0, 0 );
  1976.  
  1977.   (*Start SoundEngine;*)
  1978.   SoundInit;
  1979.   if parms.sound then begin
  1980.     LoadWav('car.wav',MainWav);
  1981.     LoadWav('impact.wav',CrashWav);
  1982.  
  1983.     InitVoice(0,MainWav,1,TRUE); (*Players Engine*)
  1984.     SetVoiceVol(0,100,100);
  1985.     SetVoiceRate(0,15000);
  1986.  
  1987.     InitVoice(1,MainWav,1,TRUE); (*Skid*)
  1988.     SetVoiceVol(1,80,80);
  1989.     SetVoiceRate(1,100000);
  1990.  
  1991.     InitVoice(2,CrashWav,1,FALSE); (*Crash, no Looping*)
  1992.     SetVoiceVol(2,100,100);
  1993.     SetVoiceRate(2,3000);
  1994.   end;
  1995.   (*Start Timer-Thread + Create Semaphore*)
  1996.  
  1997.   DosCreateEventSem(PCHAR(0),TimerEvent,DC_SEM_SHARED,FALSE);
  1998.  
  1999.   DosCreateThread(tidTimer,@TimerThread,0,0,8192);
  2000.  
  2001.   DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL,
  2002.                       -1, tidTimer );
  2003.  
  2004.   (*Create Game-Blitter Synchronization Semaphore*)
  2005.   DosCreateEventSem(PCHAR(0),BlitEvent,DC_SEM_SHARED,FALSE);
  2006.  
  2007.   (*Create Game-Blitter Synchronization Semaphore*)
  2008.   DosCreateMutexSem(PCHAR(0),SimDataAccess,DC_SEM_SHARED,FALSE);
  2009.  
  2010.   (*Start Game-Control-Thread *)
  2011.   If parms.Test then
  2012.     DosCreateThread ( tidGame,@Tester,0, 0, 8192)
  2013.   else
  2014.     DosCreateThread ( tidGame,@RaceGame,0, 0, 8192);
  2015.  
  2016.   DosSetPriority ( PRTYS_THREAD, PRTYC_REGULAR,
  2017.                       0, tidGame );
  2018.  
  2019.   (*Start Blitter-Thread *)
  2020.  
  2021.   if DosCreateThread ( tidBlitThread,
  2022.                        @BlitterThread,
  2023.                        ULONG(@win_Data), 0, 16384)<>0 then begin
  2024.     WinSetVisibleRegionNotify ( win_Data.hwndClient, FALSE ); (*!!!!*)
  2025.  
  2026.     DiveFreeImageBuffer ( win_Data.hDive, ulImage );
  2027.  
  2028.     DiveClose ( win_Data.hDive );
  2029.  
  2030.     WinDestroyWindow ( win_Data.hwndFrame );
  2031.     WinDestroyMsgQueue ( h_mq );
  2032.     WinTerminate ( h_ab );
  2033.     Halt(1);
  2034.   end;
  2035.  
  2036.   (* Set the priority of the blitting thread
  2037.   *)
  2038.   DosSetPriority ( PRTYS_THREAD, (*PRTYC_REGULAR*) PRTYC_IDLETIME,
  2039.                       20, tidBlitThread );
  2040.  
  2041.  
  2042.   (* While there are still messages, dispatch them.
  2043.   *)
  2044.   while WinGetMsg ( h_ab, q_msg, 0, 0, 0 ) do
  2045.     WinDispatchMsg ( h_ab, q_msg );
  2046.  
  2047.   (* Set the variable to end the running thread, and wait for it to end.
  2048.   *)
  2049.   SoundDone;
  2050.  
  2051.   PauseDisplay:=FALSE;
  2052.   ulToEnd := 1;
  2053.   DosWaitThread ( tidBlitThread, DCWW_WAIT );
  2054.  
  2055.   (* Turn off visible region notificationm tidy up, and terminate.
  2056.   *)
  2057.  
  2058.   WinSetVisibleRegionNotify ( win_Data.hwndClient, FALSE ); (*!!!!*)
  2059.  
  2060.   (* Free the buffers allocated by DIVE and close DIVE
  2061.   *)
  2062.   DiveFreeImageBuffer ( win_Data.hDive, ulImage );
  2063.  
  2064.   DiveClose ( win_Data.hDive );
  2065.  
  2066. (*   for  ( i = 0; i < pwin_data^.ulMaxFiles; i++ )
  2067.        DosFreeMem ( pPalette[i] );*)
  2068.  
  2069.    (* Process for termination
  2070.    *)
  2071.   DosWaitThread ( tidTimer, DCWW_WAIT );
  2072.   DosCloseEventSem(TimerEvent);
  2073.  
  2074.  
  2075.  
  2076.   WinDestroyWindow ( win_Data.hwndFrame );
  2077.   WinDestroyMsgQueue ( h_mq );
  2078.   WinTerminate ( h_ab );
  2079.   Halt(0);
  2080. end.
  2081.  
  2082.  
  2083.