home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / ARK.ARJ / SERVICE.PAS < prev    next >
Pascal/Delphi Source File  |  1995-07-07  |  113KB  |  3,176 lines

  1. {$F+}
  2.  
  3. unit service;
  4.  
  5. { ------------------------------------------------------------------------- }
  6.                                  interface
  7. { ----------------------------------------------------------------------- }
  8.  
  9.  
  10. uses crt,dos,graph,mouse,snd;
  11.  
  12. const
  13.    SCRMIN     = 10;  { Coordinata X del bordo sinistro dell'area di gioco }
  14.    SCRMAX     = 216; { Coordinata X del bordo destro dell'area di gioco }
  15.    SCRTOP     = 12;  { Coordinata Y del bordo superiore dell'area di gioco }
  16.    SCRBOT     = 200; { Coordinata Y del bordo inferiore dell'area di gioco }
  17.  
  18.    VAUS_W     = 34;  { Larghezza in pixel del VAUS }
  19.    VAUS_H     = 4;   { Altezza in pixel del VAUS }
  20.    VAUS_LINE  = 184; { Coordiana Y su cui scorre orizzontalmente il VAUS }
  21.    EMP        = -1;  { Uso EMP (empty) al posto di -1 }
  22.    BALLDIM    = 5;   { Diametro della pallina (in pixel) }
  23.    BALLSPOT   = 3;   { Raggio della pallina (in pixel) = diametro/2 +1 }
  24.  
  25.    BALLARRAY  : array[0..4,0..4] of byte = ((0,1,1,1,0),
  26.                                             (1,1,2,1,1),
  27.                                             (1,2,1,1,1),
  28.                                             (1,1,1,1,1),
  29.                                             (0,1,1,1,0));
  30.                                             { Disegno della pallina }
  31.  
  32.  
  33.    BALLDEV    = 30; { Angolo di deviazione quando }
  34.                     { urta i bordi rossi del VAUS }
  35.    SPEEDFLASH = 10; { Numero di 50-esimi di secondo che deve aspettare }
  36.                     { prima di cambiare il colore dei bordi del vaus }
  37.  
  38.    FLASH      : array[0..10] of byte = ( 255,212,211,210,209,
  39.                                          208,207,206,205,204,203);
  40.  
  41.          { Colori che gli estremi del vaus assumono durante il lampeggio }
  42.  
  43.    SCORE_WALL : array[1..10] of integer = ( 10,20,30,40,50,100,200,250,500,1000 );
  44.  
  45.  
  46.    EMERG_DEV  : array[1..8] of byte = ( $02,$13,$24,$35,$12,$23,$34,$45 );
  47.  
  48.  
  49.    COLORBLOCK : array[0..9] of byte = ( 212,211,210,209,208,
  50.                                         207,206,205,204,203 );
  51.                                          { Colore dei mattoncini }
  52.  
  53.  
  54.  
  55.    GRAYDOWN   = 1;   { Numero di colpi-1 per abbattere un mattone grigio }
  56.    STARTWALL  = 01;  { Livello di partenza }
  57.    BALLSPEED  = 500; { Velocita' della pallina (256 = 70 pixel al secondo  }
  58.    MAXSPEED   = 2000;{ Velocita' massima raggiungibile dalla pallina       }
  59.    MAXBRWHIT  = 100; { Numero massimo di blocchi indistr. che puo' colpire }
  60.                      { prima di schizzare via cambiando velocita'          }
  61.  
  62.    PATNUMBER  = 4;   { Numero dei fondali disponibili }
  63.  
  64.    POS_DIGIT  : array[1..3] of integer = (60,93,128);
  65.    { Coordinata y dei tre punteggi (player 1, player 2, hiscore) }
  66.  
  67.  
  68.    DIGITS     : array[0..10] of byte = ( 125,96,55,103,106,79,
  69.                                           95,97,127,111,0 );
  70.    { Dati per la visualizzazione delle cifre digitali nei punteggi }
  71.  
  72.    LEVEL      : array[1..5] of integer = (1000,300,100,60,35);
  73.  
  74.    SBDIR      = 600; { Cicli che deve fare prima che la palla devi (dev. regolare) }
  75.    DEFLEVEL   = 3;   { Livello di gioco di default }
  76.  
  77.    LETTER_PROB= 300; { range in cui viene estratto il numero casuale della lettera }
  78.    LETTER_DROP= 1000;{ numero che deve raggiungere la somma per far cadere la lettera }
  79.    LETTER_NUMB= 8;   { numero di lettere+1 }
  80.    LETTER_FRM = 8;   { numero dei frames che costituiscono l'animazione della lettera }
  81.    LETTER_SBF = 5;   { numero di cicli che deve compiere prima di passare al frame }
  82.                      { successivo }
  83.  
  84.    {Prob in % di caduta delle lettere }  {  L   E  B   D   S   C  P }
  85.    LETTER_DIS : array[1..7] of integer = ( 16, 20, 3, 18, 20, 20, 3 );
  86.  
  87.    FLUXLEVEL  = 176;
  88.  
  89. type
  90.  
  91.    arr768   = array[0..767] of byte;   { per i 256 colori in RGB (x3) }
  92.    arr64k   = array[0..64000] of byte; { per la schermata di 320x200  }
  93.  
  94.    BTMTYPE  = RECORD                   { per un disegno in fomrato BTM }
  95.               width   : word;          { larghezza disegno       }
  96.               height  : word;          { altezza                 }
  97.               trasp   : byte;          { trasparenza (non usato) }
  98.               palette : ^arr768;       { puntatore alla palette di colori }
  99.               palused : boolean;       { flag TRUE = la palette esiste }
  100.               map     : ^arr64k;       { dati contenenti il disegno }
  101.               end;
  102.  
  103.    VAUSTYPE = RECORD                   { per i dati del vaus }
  104.               x,y,                     { attuali coordinate x,y }
  105.               oldx,                    { vecchie coordinate del vaus }
  106.               oldy   : longint;
  107.               oldlen : integer;        { e vecchia lunghezza }
  108.               width,                   { larghezza }
  109.               height : integer;        { spessore (o altezza) }
  110.               flash  : byte;           { indica il colore attuale dei bordi }
  111.               iflash : integer;        { contatore di ritardo per il }
  112.                                        { il lampeggio dei bordi }
  113.               letter : integer;
  114.               end;
  115.  
  116.  
  117.    BALLTYPE = RECORD                   { contiene i dati della pallina }
  118.               x,y,                     { coordinate x,y attuali }
  119.               finex,finey,             { sottomultipli delle coordinate }
  120.               oldx,oldy,               { vecchie coordinate }
  121.               speed  : longint;        { velocita' (256 = 70 pixel al sec. }
  122.               finespeed : longint;     { velocita' (sottomultiplo) }
  123.               speedx,                  { velocita' sull'asse x }
  124.               speedy : longint;        { velocita' sull'asse y }
  125.               sbd    : longint;        { per evitare i loop della pallina }
  126.               brwhit : integer;        { n. di blocchi marroni colpiti di seguito }
  127.               attrib : integer;        { atributi (non usato)  }
  128.               inplay : boolean;        { flag, TRUE se la palla e' in gioco }
  129.               launch : boolean;        { flag, TRUE se la palla deve essere }
  130.                                        { ancora lanciata }
  131.               onvaus : integer;        { larghezza in pixel del vaus }
  132.               stm    : integer;        { contatore di calamita }
  133.               end;
  134.  
  135.    WALLTYPE = array[0..12,-1..15] of byte; { per il muro (13x15 mattoncini) }
  136.  
  137.    WHOLEWALLS = array[0..33] of WALLTYPE; { per tutti e 33 i muri }
  138.  
  139.    SCORETYPE  = RECORD                           { tiene i punteggi }
  140.                 player : array[1..2] of longint; { player 1 e 2 }
  141.                 wall_n : array[1..2] of integer; { muro corrente }
  142.                 wall_p : array[1..2] of WALLTYPE;{ memoriz. del muro stesso }
  143.                 lives  : array[1..2] of integer; { vite rimaste }
  144.                 hiscore: longint;                { record }
  145.                 pl_numb: integer;                { giocatore corrente }
  146.                 roundsel : array[1..2] of boolean;
  147.                 abortplay : boolean;
  148.                 end;
  149.  
  150.    SHREC      = RECORD                 { per lo scintillio dei mattoncini }
  151.                 xb,yb,frame : integer;
  152.                 block       : integer;
  153.                 active      : boolean;
  154.                 end;
  155.  
  156.    LETTERREC  = RECORD                 { dati relativi alla lettera }
  157.                 x,y      : word;       { coord. }
  158.                 typ      : integer;    { Tipo, B,C,E,L,P,D,S }
  159.                 frame    : integer;    { numero del frame }
  160.                 subframe : integer;    { numero di cicli per ogni frame }
  161.                 active   : boolean;    { la lettera puo' essere attiva }
  162.                 incoming : longint;    { tiene la somma, >1000 la lettera cade }
  163.                 nextx,                 { coord di dove deve cadere se attivata }
  164.                 nexty,
  165.                 nexttype : word;       { tipo di lettera che dovra' cadere }
  166.                 last     : integer;    { ultima lettera caduta }
  167.                 end;
  168.  
  169.    FIRETYPE   = RECORD                 { per i laser }
  170.                 x,y  : word;           { coord. }
  171.                 shot : boolean;        { se il colpo e' partito }
  172.                 avl  : boolean;        { se e' dispoibile (grazie alla L) }
  173.                 nw   : boolean;        { se e' appena partito dal VAUS }
  174.                 end;
  175.  
  176. var
  177.     playscreen : BTMTYPE;  { area di gioco (320x200) }
  178.     playvaus   : BTMTYPE;  { vaus }
  179.     normal     : BTMTYPE;  { vaus normale }
  180.     enlarged   : BTMTYPE;  { allargato }
  181.     lasers     : BTMTYPE;  { traformato per sparare }
  182.     pattern    : BTMTYPE;  { sfondo }
  183.     explosion  : BTMTYPE;  { esplosione vaus }
  184.     newvaus    : BTMTYPE;  { sequenza di animazione di partenza }
  185.     presents   : BTMTYPE;  { scritta ARKANOID }
  186.     soundfx    : BTMTYPE;  { l'icona con la nota e la nota sbarrata }
  187.     shinewall  : BTMTYPE;  { luccichio dei mattoncini grigi e beige }
  188.     minivaus   : BTMTYPE;  { vaus piccolino che indica le vite }
  189.     levelsel   : BTMTYPE;  { 5 frames dei numeri per scegliere il livello }
  190.     letters    : BTMTYPE;  { le animazioni delle 7 lettere }
  191.     shoots     : BTMTYPE;  { e il disegno dei laser }
  192.     flux       : BTMTYPE;
  193.     vaus       : VAUSTYPE; { dati relativi al vaus (vedi sopra) }
  194.  
  195.     row        : array[0..250] of word; { array (vedere initRowArray) }
  196.     success    : boolean;               { flag di stato per il caric. BTM }
  197.  
  198.     screen     : array[0..65530] of byte absolute $a000:0000;
  199.                { forzatura della mappa di schermo all'indirizzo della VGA }
  200.                { a000:0000 inerente alla modalita' grafica 320x200x256 col. }
  201.  
  202.     wall       : walltype;  { muro }
  203.     cn         : integer;   { variabile di servizio usata qua e la' }
  204.     modx       : array[0..319] of integer;
  205.     mody       : array[0..199] of integer;
  206.     all_walls  : WHOLEWALLS;                 { tutti i muri }
  207.     remain_blk : integer;                    { mattoni ancora da abbattere }
  208.     totalwall  : integer;                    { mattoni in tutto }
  209.     score      : SCORETYPE;                  { punteggio corrente }
  210.     cur_player : integer;                    { giocatore corrente }
  211.     shinerec   : shrec;                      { tiene i dati dell'blocco }
  212.                                              { che scintilla in questo }
  213.                                              { momento }
  214.     lv         : integer;                    { livello di gioco }
  215.     trainer    : integer;
  216.  
  217.     lett       : LETTERREC;                  { i parametri delle lettere }
  218.     fire       : FIRETYPE;                   { e dei raggi laser         }
  219.     balls_in_play : integer;                 { numero di palline in gioco }
  220.     scrflux    : boolean;
  221.     scrfluxcnt : integer;
  222.  
  223. { ------------------------------------------------------------------------- }
  224.  
  225. { Queste sono le funzioni che devono essere viste dal programma principale }
  226.  
  227. function  mainscreen : integer;
  228. procedure fatal_error(err_type : string);
  229. procedure loadBTM(name : string; var BTMREC : BTMTYPE; pal : boolean);
  230. procedure load_all_walls;
  231. procedure InitSVGA;
  232. procedure initRowArray;
  233. function  random_letter_drop : integer;
  234. procedure start_game(players : integer);
  235. procedure closeprogram;
  236.  
  237. { ------------------------------------------------------------------------- }
  238.                               implementation
  239. { ------------------------------------------------------------------------- }
  240.  
  241. procedure closeprogram;
  242.   begin
  243.   clrscr;
  244.   textcolor(7);
  245.   writeln('Important!');
  246.   writeln;
  247.   writeln('This game is only a demostration of how is possible to build');
  248.   writeln('sophisticated programs, even in Turbo Pascal, using a powerful');
  249.   writeln('shareware utility whose name is Power Design 386 (or PD386 for short).');
  250.   writeln('PD386 offers all the features you need to create multicolored sprites');
  251.   writeln('and pictoresque background screens for your games, your aplications');
  252.   writeln('and your programs in general. It also supports the .GIF graphic format!');
  253.   writeln('If you are interested in programming graphics you cannot miss PD386.');
  254.   writeln('Please take a look.');
  255.   writeln;
  256.   writeln('End of message.');
  257.   halt;
  258.   end;
  259.  
  260. { ritorna il massimo fra a e b }
  261. function max(a,b : integer) : integer;
  262.   begin
  263.   if(a>b) then max:=a
  264.   else max:=b;
  265.   end;
  266.  
  267. { idem per il minimo }
  268. function min(a,b : integer) : integer;
  269.   begin
  270.   if(a<b) then min:=a
  271.   else min:=b;
  272.   end;
  273.  
  274.  
  275. { chiara, no? }
  276. procedure fatal_error(err_type : string);
  277.  
  278.    begin
  279.    nosound;
  280.    closegraph;
  281.    write;
  282.    writeln('Arkanoid can run no long');
  283.    writeln('Fatal Error: ',err_type);
  284.    halt;
  285.    end;
  286.  
  287. function inkey : word;   { restituisce il codice del tasto premuto }
  288. var ch,ch2: char;        { 0 = nessun tasto premuto }
  289.     begin
  290.     ch:=#0;
  291.     ch2:=#0;
  292.  
  293.     if keypressed then
  294.        begin
  295.        ch:=readkey;
  296.        if ch=#0 then ch2:=readkey;
  297.        end;
  298.  
  299.     inkey:=(ord(ch2)*256)+ord(ch);
  300.     end;
  301.  
  302. procedure initRowArray;  { inizializza l'array ROW; row[n]:=320*n }
  303. var y : word;
  304.   begin
  305.   for y:=0 to 199 do
  306.     row[y]:=y*320;
  307.  
  308.   for y:=200 to 250 do
  309.     row[y]:=64000;
  310.  
  311.   end;
  312.  
  313. { quanto segue fa parte della procedura per installare un driver esterno }
  314. { come da esempio nell'help di Turbo Pascal.                             }
  315.  
  316. procedure svgadrv; external; {$L SVGADRV.OBJ}
  317.  
  318. function DetectVGA : Integer;
  319.   begin
  320.   DetectVGA := 0;
  321.   end;
  322.  
  323. procedure InitSVGA; { Inizializza il driver della SuperVGA come da esempio }
  324. var
  325.    AutoDetect : pointer;
  326.    GraphMode, GraphDriver, ErrCode: integer;
  327.  
  328.    begin
  329.     GraphDriver := InstallUserDriver('SVGA256',@DetectVGA);
  330.    if RegisterBGIDriver(@svgadrv)<0 then
  331.       fatal_error('Unable to register driver');
  332.  
  333.     ErrCode:=GraphResult;
  334.     if ErrCode <> grOk then
  335.         begin
  336.         WriteLn('Error installing TestDriver:');
  337.         Writeln(GraphErrorMsg(ErrCode));
  338.         Halt(1);
  339.         end;
  340.     GraphDriver:=Detect;
  341.     InitGraph(GraphDriver,GraphMode,'');
  342.     ErrCode := GraphResult;
  343.     if ErrCode <> grOk then
  344.         begin
  345.         WriteLn('Error during Init: ', GraphErrorMsg(ErrCode));
  346.         Halt(1);
  347.         end;
  348.  
  349.    end; { Fine della procedura InitSVGA }
  350.  
  351. { ------------------------------------------------------------------------ }
  352.  
  353. procedure shine_block;    { esegue lo scintillio di un blocco }
  354. var
  355.     xb,yb,                { i parametri del blocco sono contenuti nella }
  356.     frame : word;         { variabile globale SHINEREC }
  357.     x,y,
  358.     xf,yf,
  359.     fr,og : word;
  360.  
  361.     begin
  362.     xb   :=shinerec.xb;   { mette in xb,yb le coordinate del blocco }
  363.     yb   :=shinerec.yb;
  364.  
  365.     if wall[xb,yb]>8 then { se il blocco e grigio o marrone }
  366.        begin
  367.        frame:=(shinerec.frame shr 1);        { calcola il n. del frame }
  368.        if wall[xb,yb]<>10 then inc(frame,5);
  369.  
  370.        xf:= 9+(xb shl 4);  { trova le coordinate sullo shermo del blocco }
  371.        yf:=22+(yb shl 3);  { da far scintillare }
  372.        fr:=frame  shl 7;   { si calcola la posizione del n-esimo frame }
  373.  
  374.        for y:=0 to 7 do    { e copia il frame n-esimo sullo schermo }
  375.            begin
  376.            og:=y shl 4;      { equivale ad y*16, ma piu' veloce }
  377.            memcpy(addr(shinewall.map^[fr+og]),addr(screen[xf+row[yf+y]]),16);
  378.            end;
  379.        end;
  380.  
  381.     inc(shinerec.frame);  { incrementa il frame counter }
  382.     if shinerec.frame=10 then shinerec.active:=FALSE;
  383.     { e quando il frame e' l'ultimo allora lo scintillio e' finito }
  384.  
  385.     end;
  386.  
  387. procedure unshine_block; { interrompe lo scintillio di un blocco se la }
  388.                          { palla urtandone un altro causa lo scintillio }
  389.                          { di un altro blocco }
  390.     begin
  391.     shinerec.frame:=9;   { cioe' setta il frame come ultimo }
  392.     shine_block;         { ed esegue lo scintillio del blocco con l'ultimo }
  393.                          { frame, cioe' il blocco torna normale }
  394.     end;
  395.  
  396. procedure shine(xb,yb : integer);   { questa procedura imposta lo }
  397.                                     { scintillio di un blocco }
  398. var t : integer;
  399.     begin
  400.     if shinerec.active then unshine_block;
  401.  
  402.     shinerec.xb    :=xb;  { coordinate del blocco }
  403.     shinerec.yb    :=yb;  { x,y }
  404.     shinerec.frame :=0;   { frame di partenza }
  405.     shinerec.active:=TRUE;        { scintillio attivo }
  406.     shinerec.block :=wall[xb,yb]; { tipo di blocco (marrone o grigio) }
  407.     end;
  408.  
  409. procedure checkshine; { se lo scintillio e' attivato allora lo esegue }
  410.                       { passando al frame successivo }
  411.     begin
  412.     if shinerec.active=TRUE then shine_block;
  413.     end;
  414.  
  415.  
  416. function random_letter_drop : integer;
  417. var rn,sum,letter : integer;
  418.    begin
  419.    repeat
  420.       rn:=random(100);  { Tira a caso un numero fra 0 e 99 }
  421.       sum:=0;           { pone la somma a zero             }
  422.       letter:=0;        { e la lettera corrente a 0        }
  423.  
  424.       repeat
  425.  
  426.  
  427.          inc(letter);                   { Incrementa la lettera corrente }
  428.          inc(sum,LETTER_DIS[letter]);   { Incrementa somma della percentuale di }
  429.                                         { probabilita' della lettera corrente }
  430.  
  431.       until sum>rn; { Se la somma oltrepassa il numero casuale scelto }
  432.                     { il programma fa cadere la lettera corrente      }
  433.                     { altrimenti passa alla lettera dopo.             }
  434.  
  435.    until (letter-1)<>lett.last;
  436.  
  437.    random_letter_drop:=(letter-1);
  438.    end;
  439.  
  440. procedure put_letter;
  441. var xl,yl,fl,fw,cl : word;
  442.  
  443.     begin
  444.     fl:=(lett.typ shl 10)+(lett.frame shl 4);
  445.  
  446.     for yl:=0 to 7 do
  447.         begin
  448.         fw:=yl shl 7;
  449.         memzerocpy(addr(letters.map^[fw+fl]),addr(screen[lett.x+row[lett.y+yl]]),16);
  450.         end;
  451.     end;
  452.  
  453. procedure remove_letter;
  454. var ad,yl : word;
  455.  
  456.     begin
  457.     if (lett.x>=0) and (lett.x<320) and (lett.y>0) and (lett.y<240) then
  458.        begin
  459.        for yl:=0 to 7 do
  460.            begin
  461.            ad:=lett.x+row[lett.y+yl];
  462.            if ad<64000 then
  463.               memcpy(addr(playscreen.map^[ad]),addr(screen[ad]),16);
  464.            end;
  465.        end;
  466.     end;
  467.  
  468. procedure disable_letter;
  469.    begin
  470.    remove_letter;
  471.    lett.active:=FALSE;
  472.    end;
  473.  
  474. procedure start_letter(xl,yl,letter : word);
  475.    begin
  476.    if lett.active then disable_letter;
  477.  
  478.    with lett do
  479.       begin
  480.       x       :=xl;
  481.       y       :=yl;
  482.       typ     :=letter;
  483.       frame   :=0;
  484.       subframe:=0;
  485.       active  :=TRUE;
  486.       end;
  487.    end;
  488.  
  489. procedure check_letter;
  490.    begin
  491.    if lett.active then
  492.       begin
  493.       remove_letter;
  494.       inc(lett.y);
  495.       if lett.y>=200 then disable_letter
  496.       else
  497.         begin
  498.         put_letter;
  499.         inc(lett.subframe);
  500.         if lett.subframe=LETTER_SBF then
  501.            begin
  502.            lett.subframe:=0;
  503.            inc(lett.frame);
  504.            end;
  505.  
  506.         if lett.frame=LETTER_FRM then lett.frame:=0;
  507.  
  508.         if (vaus.x<(lett.x+16)) and ((vaus.x+vaus.width)>lett.x) and
  509.            (vaus.y<(lett.y+8))  and ((vaus.y+vaus.height)>lett.y) then
  510.            begin
  511.            ball_block_sound(100,10);
  512.            vaus.letter:=lett.typ+1;
  513.            inc(score.player[cur_player],SCORE_WALL[10]);
  514.            disable_letter;
  515.            end;
  516.         end;
  517.  
  518.       lett.incoming:=0;
  519.       end
  520.    else if (lett.incoming>LETTER_DROP) then
  521.         with lett do start_letter(nextx,nexty,nexttype);
  522.    end;
  523.  
  524. { Copia sullo schermo a partire dalla coordinata 0,0 il disegno specificato }
  525. procedure showBTMpicture(BTM : BTMTYPE);
  526. var x,y,ofst : word;
  527.  
  528.   begin
  529.   for y:=0 to BTM.height-1 do   { la y varia da 0 all'altezza-1 del disegno }
  530.      begin
  531.      ofst:=y*BTM.width;         { calcola l'indirizzo nella matrice del dis.}
  532.      for x:=0 to BTM.width-1 do
  533.         screen[x+row[y]]:=BTM.map^[x+ofst]; { mette il disegno sullo schermo }
  534.      end;
  535.   end;
  536.  
  537. procedure setpalette(var BTM : BTMTYPE);
  538. var regs : REGISTERS;
  539.  
  540.   begin
  541.   regs.ax:=$1012;               { setta i colori usando l'interrupt 10h }
  542.   regs.bx:=0;                   { del BIOS }
  543.   regs.cx:=256;
  544.   regs.es:=SEG(BTM.palette^);
  545.   regs.dx:=OFS(BTM.palette^);
  546.   intr($10,regs);
  547.   end;
  548.  
  549. procedure loadBTM(name : string; var BTMREC : BTMTYPE; pal : boolean);
  550. var
  551.   h1   : file;
  552.   s    : array[0..10] of byte;   { carica un file in formato BTM }
  553.   cnt  : word;
  554.   size : longint;
  555.   pl   : array[0..767] of byte;
  556.  
  557.   begin
  558.   {$I-}
  559.   assign(h1,name);               { apre il file }
  560.   reset(h1,1);                   { e si pone all'inizio }
  561.  
  562.   blockread(h1,s,11,cnt);        { legge 11 bytes di intestazione }
  563.   blockread(h1,pl,768,cnt);      { legge la palette dei colori }
  564.  
  565.   BTMREC.width :=s[6]+s[7]*256;  { legge la larghezza, byte 6 e 7 }
  566.   BTMREC.height:=s[8]+s[9]*256;  { l'altezza, byte 8 e 9 }
  567.   BTMREC.trasp :=s[10];          { e il colore di trasparenza }
  568.  
  569.   size:=(BTMREC.width)*(BTMREC.height); { calcola dimensione immagine }
  570.  
  571.   getmem(BTMREC.map,size);              { alloca la memoria per l'immagine }
  572.   blockread(h1,BTMREC.map^,size,cnt);   { e si legge l'immagine da disco }
  573.  
  574.   if pal=TRUE then                 { se occorre tenere anche la palette }
  575.      begin
  576.      getmem(BTMREC.palette,768);   { alloca la mem. per la palette }
  577.      for cnt:=0 to 767 do
  578.          BTMREC.palette^[cnt]:=pl[cnt]; { e ci copia la palette appena }
  579.                                         { caricata che altrimenti verrebbe }
  580.                                         { perduta al termine della proc. }
  581.      BTMREC.palused:=TRUE; { quindi setta a TRUE il flag PALETTE USATA }
  582.      end
  583.  
  584.   else BTMREC.palused:=FALSE; { altrimenti lo setta a false }
  585.  
  586.   close(h1);  { e chiude il file letto da disco }
  587.   {$I+}
  588.  
  589.   if IOResult<>0 then success:=FALSE;
  590.   end;
  591.  
  592.  
  593. { disegna la palla sullo schermo, le coordinate sono specificate in }
  594. { BALL.x e BALL.y, BALLSPOT.x = BALLSPOT.y e' il raggio della palla }
  595. { in pixel }
  596. procedure place_ball(var ball : BALLTYPE);
  597. var xp,yp,adr : longint;
  598.   begin
  599.   for yp:=0 to BALLDIM-1 do
  600.      begin
  601.      adr:=ball.x-BALLSPOT+row[yp-BALLSPOT+ball.y];
  602.      memzerocpy(addr(BALLARRAY[yp,0]),addr(screen[adr]),BALLDIM);
  603.      end;
  604.   end;
  605.  
  606. { Cancella la palla dallo schermo, viene chiamata un istante prima di }
  607. { place_ball }
  608. procedure remove_ball(var ball: BALLTYPE);
  609. var
  610.   xp,
  611.   yp   : longint;
  612.   temp : longint;
  613.  
  614.   begin
  615.   for yp:=0 to BALLDIM-1 do
  616.       begin
  617.       temp:=ball.oldx-BALLSPOT+row[yp-BALLSPOT+ball.oldy];
  618.       if (temp>0) and (temp<64000) then
  619.          memcpy(addr(playscreen.map^[temp]),addr(screen[temp]),BALLDIM);
  620.       end;
  621.   end;
  622.  
  623. procedure Wait_VBL;
  624. label ALTO,BASSO;
  625.    begin
  626.       { questa porzione di codice assembler attende che il pennello }
  627.       { elettronico del monitor sia nella posizione di vertical blank }
  628.       { in modo da evitare lo sfarfallamento dell'immagine. }
  629.  
  630.       { provvede anche a temporizzare la CPU regolando la velocita' di }
  631.       { esecuzione del programma indipendentemente dal tipo di processore }
  632.  
  633.       { ogni scheda VGA in modalita' 320x200x256 col. lavora ad una }
  634.       { frequenza di 70Hz. }
  635.  
  636.       asm
  637.       mov  dx,$03da
  638.  
  639.       BASSO:
  640.       in   al,dx
  641.       test al,8
  642.       jz   BASSO
  643.  
  644.       ALTO:
  645.       in   al,dx
  646.       test al,8
  647.       jnz  ALTO
  648.       end;
  649.  
  650.    end;
  651.  
  652. procedure set_ball(var ball : BALLTYPE);
  653.   begin
  654.   if((ball.oldx<>EMP) and (ball.oldy<>EMP)) and
  655.     ((ball.oldx<>ball.x) or (ball.oldy<>ball.y)) then
  656.       remove_ball(ball); { appena ha inizio il VB si sposta la palla alle }
  657.  
  658.   place_ball(ball);  { nuove coordinate }
  659.  
  660.   ball.oldx:=ball.x; { si settano le vecchie coordinate uguali a quelle }
  661.   ball.oldy:=ball.y; { correnti, le correnti verrano modificate poi }
  662.   end;
  663.  
  664. procedure set_ball_speed(var ball : BALLTYPE; speed : longint);
  665. var
  666.   sx,sy : longint;  { imposta la velocita' della palla in base al modulo }
  667.   vm    : real;     { del vettore velocita' passato in SPEED : longint.  }
  668.  
  669.   begin
  670.   sx:=ball.speedx;  { memorizza le componenti x e y della velocita' }
  671.   sy:=ball.speedy;  { rispettivamente in sx ed sy }
  672.  
  673.   vm:=speed / sqrt(sx*sx+sy*sy); { calcola il coef. di proporzionalita'  }
  674.                                  { fra la vecchia e la nuova velocita'   }
  675.                                  { (la direzione non cambia, cambia solo }
  676.                                  { il modulo). }
  677.  
  678.   ball.speedx:=round(sx * vm);   { e quindi moltiplica per tale coef. }
  679.   ball.speedy:=round(sy * vm);   { le due proiezioni della velocita'. }
  680.  
  681.   end;
  682.  
  683. procedure set_ball_direction(var ball : BALLTYPE; angle : integer);
  684. var w : real;
  685.   begin                  { imposta l'angolo di traiettoria della palla }
  686.   w:=angle*3.14/180.0;   { w viene espresso in gradi }
  687.  
  688.   ball.speedx:=round(256*cos(w));  { la velocita' si suppone unitaria }
  689.   ball.speedy:=-round(256*sin(w)); { v=256 equivale a 70 pixel al sec. }
  690.   end;
  691.  
  692. function get_ball_direction(var ball : BALLTYPE): integer;
  693. var w : integer; { restituisce la direzione in cui si muove la palla }
  694.   begin
  695.   if ball.speedx=0 then w:=-90*(ball.speedy div abs(ball.speedy))
  696.   else
  697.     begin
  698.     { calcola l'arcotangente e aggiunge multipli di 90 gradi a seconda dei }
  699.     { segni di ball.speedx e ballspeed.y }
  700.  
  701.     w:=round(arctan(-ball.speedy/ball.speedx)*180.0/3.14);
  702.     if(ball.speedx<0) then inc(w,180);
  703.     inc(w,360);
  704.     w:=w mod 360;
  705.     end;
  706.  
  707.   get_ball_direction:=w;
  708.   end;
  709.  
  710. procedure start_ball(var ball : BALLTYPE);
  711.   begin
  712.   { inizializza i parametri della palla quando questa deve essere }
  713.   { lanciata dal vaus. }
  714.  
  715.   ball.x:=vaus.x+ball.onvaus;
  716.  
  717.                      { la coord. di partenza e' quella del vaus+16 }
  718.                      { cioe' essendo il vaus di 34 pixel, la palla deve }
  719.                      { partire al centro del vaus, cioe' vaus.x+16 }
  720.  
  721.   ball.y:=vaus.y-BALLSPOT;
  722.                            { chiaramente il centro della palla sara' sulla }
  723.                            { linea dove scorre il vaus, meno il raggio }
  724.                            { della palla }
  725.  
  726.   ball.finex:=0;   { e i due sottomultipli della posizione sono 0 }
  727.   ball.finey:=0;
  728.  
  729.   ball.inplay:=TRUE; { setta il flag che memorizza se la palla e' in gioco }
  730.  
  731.   ball.sbd:=0;
  732.   ball.brwhit:=0;
  733.   end;
  734.  
  735. function ball_speed(ball : BALLTYPE): integer;
  736.   begin
  737.   { restituisce il modulo della velocita' della palla, usa il teorema di }
  738.   { pitagora (v=sqrt(x^2+y^2)) }
  739.  
  740.   ball_speed:=round(sqrt(ball.speedx*ball.speedx+ball.speedy*ball.speedy));
  741.   end;
  742.  
  743. procedure move_ball(var ball : BALLTYPE);
  744. var
  745.   x,y,z : longint;
  746.   angle : integer;
  747.  
  748.   begin
  749.   { muove la palla sommando alle coordinate x,y i due vettori velocita' }
  750.   { prima di eseguire tale somma viene moltiplicato tutto per 256 in modo }
  751.   { da avere un numero di posizioni piu' elevato. }
  752.  
  753.   x:=(ball.x shl 8)+ball.finex+ball.speedx;
  754.   y:=(ball.y shl 8)+ball.finey+ball.speedy;
  755.  
  756.   ball.x:=x shr 8;
  757.   ball.y:=y shr 8;
  758.  
  759.   ball.finex:=x and $ff;
  760.   ball.finey:=y and $ff;
  761.  
  762.   { controlla se avviene un urto della pallina sulla parete di destra }
  763.   { in caso d'urto inverte il segno }
  764.  
  765.   if(ball.x>SCRMAX) then
  766.      begin
  767.      ball.speedx:=-ball.speedx;  { inverte il vettore x della velocita' }
  768.      ball.x:=2*SCRMAX-ball.x;    { riflette sull'asse x=SCRMAX la palla }
  769.      ball.finex:=255-ball.finex; { aggiusta i sottomultipli della velocita' }
  770.      ball_block_sound(240,5);    { emette il suono dell'urto sulla la parete }
  771.      end;
  772.  
  773.   { idem per la parete di sinistra }
  774.  
  775.   if(ball.x<SCRMIN) then
  776.      begin
  777.      ball.speedx:=-ball.speedx;
  778.      ball.x:=2*SCRMIN-ball.x;
  779.      ball.finex:=255-ball.finex;
  780.      ball_block_sound(240,5);
  781.      end;
  782.  
  783.   { ... e per quella superiore }
  784.  
  785.   if(ball.y<SCRTOP) then
  786.      begin
  787.      ball.speedy:=-ball.speedy;
  788.      ball.y:=2*SCRTOP-ball.y;
  789.      ball.finey:=255-ball.finey;
  790.      ball_block_sound(240,5);
  791.      end;
  792.  
  793.  
  794.   { se la palla si trova sull'ordinata del vaus, se la velocita' vy e'
  795.     maggiore di 0 (cioe' la palla si muove verso il basso), e se la
  796.     palla prima si trovava al di sopra del vaus, allora ...}
  797.  
  798.   if(ball.y+BALLSPOT>VAUS_LINE) and (ball.speedy>0) and (ball.oldy<=VAUS_LINE) then
  799.      begin
  800.      { se un qualsiasi punto della palla si trova sul vaus ... }
  801.  
  802.      if(ball.x>vaus.x-BALLSPOT) and (ball.x<vaus.x+vaus.width+BALLSPOT) then
  803.         begin
  804.         { inverte il vettore vy della velocita' della palla }
  805.         ball.speedy:=-ball.speedy;
  806.  
  807.         if (vaus.letter=6) and (not ball.launch) then
  808.            begin
  809.            ball.stm:=0;
  810.            ball.launch:=TRUE;
  811.            ball.onvaus:=ball.x-vaus.x;
  812.            end;
  813.  
  814.         ball_block_sound(300,6);
  815.         { emette il suono d'urto palla-vaus }
  816.  
  817.  
  818.  
  819.         { se la palla urta il cilindretto rosso di sinistra del vaus }
  820.         if (ball.x<vaus.x+10) then
  821.            begin
  822.            { inverte il vettore vx, velocita' x della palla }
  823.            ball.speedx:=-ball.speedx;
  824.  
  825.            { mette nella variabile angle l'angolo di movimento della palla
  826.              piu' un valore casuale di deviasione compreso fra 0 e BALLDEV }
  827.            angle:=get_ball_direction(ball)+random(BALLDEV);
  828.  
  829.            { re-imposta secondo questo nuovo angolo la direzione di movimento
  830.              della pallina. Comunque sia' l'angolo e' compreso fra 120 e 160
  831.              gradi. Valori superiori o inferiori a questo range vengono auto
  832.              maticamente riportati ai valori estremi del range stesso.
  833.              Ad esempio 175 gradi viene riportato a 160 gradi. }
  834.  
  835.            set_ball_direction(ball,max(120,min(160,angle)));
  836.  
  837.            { re-imposta la velocita' della palla, perche' cambiando l'angolo
  838.              di movimento la velocita' viene perduta. }
  839.  
  840.            set_ball_speed(ball,ball.speed);
  841.            end;
  842.  
  843.         { del tutto simile al precedente con la differenza che il discorso
  844.           viene fatto per il cilindretto rosso di destra. }
  845.  
  846.         if (ball.x>vaus.x+vaus.width-10) then
  847.            begin
  848.            ball.speedx:=-ball.speedx;
  849.            angle:=get_ball_direction(ball)-random(BALLDEV);
  850.            set_ball_direction(ball,min(60,max(20,angle)));
  851.            set_ball_speed(ball,ball.speed);
  852.            end;
  853.  
  854.         end;
  855.      end;
  856.  
  857.   { se la palla supera il vaus, senza che avvenga una collisione, vale
  858.     a dire: se entrambe, la vecchia e la nuova coordinata y sono maggiori
  859.     della dell'ordinata su cui scorre il vaus e la velocita' y della palla
  860.     e maggiore di 0, cioe' la palla si muove verso il basso, allora la palla
  861.     e' persa e il vaus viene fatto esplodere.}
  862.  
  863.   if (ball.oldy>VAUS_LINE) and (ball.y>SCRBOT) and (ball.speedy>0) then
  864.      begin
  865.      ball.inplay:=FALSE; { per adesso viene solo settato il flag, palla non
  866.                            piu' in gioco. }
  867.      remove_ball(ball);  { e si cancella la palla dallo schermo }
  868.      end;
  869.  
  870.   end;
  871.  
  872. procedure modify_vaus;
  873.   begin
  874.   vaus.oldlen:=vaus.width;
  875.   vaus.width :=playvaus.width;   { larghezza del vaus }
  876.   vaus.height:=playvaus.height;  { altezza del vaus   }
  877.   end;
  878.  
  879. procedure set_vaus; { setta i parametri iniziali (di partenza) del vaus }
  880.   begin
  881.   vaus.x:=((SCRMAX-SCRMIN) shr 1)-8;
  882.   vaus.y:=VAUS_LINE;
  883.  
  884.   vaus.oldx:=EMP;                { le vecchie coordinate vengono poste a EMP }
  885.   vaus.oldy:=EMP;                { poiche' il vaus non si e' spostato }
  886.   vaus.iflash:=0;                { Questo viene incrementato ogni 1/70 sec. }
  887.                                  { e quando arriva ad un certo valore viene }
  888.                                  { azzerato e viene incrementato vaus.flash }
  889.  
  890.   vaus.flash:=0;                 { Da questa var. dipende il colore dei }
  891.                                  { dei bordini del vaus. }
  892.                                  { (che cambia in continuazione) }
  893.  
  894.   vaus.width :=playvaus.width;   { larghezza del vaus }
  895.   vaus.height:=playvaus.height;  { altezza del vaus   }
  896.   vaus.oldlen:=vaus.width;
  897.   vaus.letter:=EMP;
  898.                                  { entrambi sono contenuti nel file .BTM }
  899.  
  900.   end;
  901.  
  902. procedure start_vaus;
  903.   begin
  904.   mouse_x_limit(SCRMIN*2,(SCRMAX-vaus.width-1) shl 1);
  905.   mousemove((SCRMAX-SCRMIN)-16,VAUS_LINE);
  906.   vaus.x:=((SCRMAX-SCRMIN) shr 1)-8;
  907.   vaus.y:=VAUS_LINE;
  908.  
  909.   { imposta il vaus al centro dell'area di gioco  }
  910.   { x=(x1+x2)/2 media fra il massimo e il minimo  }
  911.   { anche la freccina del mouse (che non si vede) }
  912.   { viene portato al centro }
  913.  
  914.   end;
  915.  
  916. procedure remove_vaus;
  917. label L1,L2,L3;
  918. var y,cnt : word;
  919.   begin
  920.   { Toglie il vaus e disegna al suo posto lo sfondo          }
  921.  
  922.   for y:=vaus.oldy to (vaus.oldy+vaus.height) do
  923.      memcpy(addr(playscreen.map^[vaus.oldx+row[y]]),
  924.             addr(screen[vaus.oldx+row[y]]),vaus.oldlen);
  925.  
  926.   vaus.oldlen:=vaus.width;
  927.   end;
  928.  
  929. procedure place_vaus;
  930. var
  931.   x,y,cnt : word;
  932.  
  933.   begin
  934.   inc(vaus.iflash);        { viene incrementato ogni ciclo (1/70 sec.) }
  935.  
  936.   if vaus.iflash>SPEEDFLASH then  { se raggiunge il valore SPEEDFLASH... }
  937.      begin
  938.      inc(vaus.flash);             { viene incrementato vaus.flash  }
  939.      vaus.iflash:=0;              { e viene riazzerato vaus.iflash }
  940.      end;
  941.  
  942.   if vaus.flash>10 then vaus.flash:=0;
  943.   { 10 sono i diversi colori che possono assumere i bordini del vaus }
  944.   { dopodiche' il ciclo si ripete dall'inizio (cioe' da 0) }
  945.  
  946.   { Disegna il vaus facendo attenzione che i bordini (che hanno colore 255 }
  947.   { nel disegno .BTM) devono essere sostituiti dal colore specificato da }
  948.   { flash[vaus.flash], dove ovviamente flash[] e' una funzione dipendente da }
  949.   { vaus.flash di cui sopra. Per esempio flash[2]:=211 (vedi all'inizio nella }
  950.   { dichiarazione delle costanti. }
  951.  
  952.   for y:=0 to vaus.height-1 do
  953.      begin
  954.      { questa moltiplicazione viene fatta qui per non ripeterla }
  955.      { vaus.width volte }
  956.      cnt:=y * vaus.width;
  957.      memzerocpy(addr(playvaus.map^[cnt]),addr(screen[vaus.x+row[y+vaus.y]]),vaus.width);
  958.  
  959.      if (y>=2) and (y<(vaus.height-2)) then
  960.         begin
  961.         screen[vaus.x+row[y+vaus.y]]:=FLASH[vaus.flash];
  962.         screen[vaus.x+vaus.width-1+row[y+vaus.y]]:=FLASH[vaus.flash];
  963.         end;
  964.      end;
  965.   end;
  966.  
  967. { muove il vaus alle coordinate x,y }
  968. procedure move_vaus(x,y : integer);
  969.   begin
  970.  
  971.   { se le coordinate oldx,oldy sono valide allora bisogna cancellarlo }
  972.   { da quella posizione }
  973.   if(vaus.oldx<>EMP) and (vaus.oldx<>vaus.x) or (vaus.width<>vaus.oldlen) then
  974.      remove_vaus;
  975.  
  976.   vaus.oldx:=vaus.x; { le nuove coordinate diventano le vecchie }
  977.   vaus.oldy:=vaus.y;
  978.  
  979.   { le coordinate x,y diventano le nuove }
  980.   { viene eseguito un clipping delle coordinate, cioe' se i valori ad }
  981.   { esempio sono troppo alti, vengono settate al massimo valore accettabile }
  982.   { analogamente per il minimo }
  983.  
  984.   vaus.x:=max(SCRMIN,min(x,(SCRMAX-vaus.width)));
  985.   vaus.y:=max(SCRTOP,min(y,(SCRBOT-vaus.height)));
  986.  
  987.   place_vaus;  { chiama la funzione placevaus di cui sopra }
  988.   end;
  989.  
  990.  
  991. { togli un mattoncino dallo schermo }
  992. procedure remove_block(xa,ya : integer);
  993. var
  994.     x,y,
  995.     xs,ys : word;
  996.     yh,cl : integer;
  997.     shadow: integer;
  998.  
  999.     begin
  1000.     xs:=(xa shl 4)+9;      { si calcola le coordinate sullo schermo }
  1001.     ys:=(ya shl 3)+22;     { del mattoncino es. 0,0 ---schermo---> 9,22 }
  1002.  
  1003.     for y:=0 to 7 do
  1004.         begin
  1005.         yh:=pattern.width*mody[ys+y]; { calcola la coord. y relativa alla }
  1006.                                       { mattonella di sfondo che deve rim-  }
  1007.                                       { piazzare il mattoncino che non c'e' }
  1008.                                       { piu' }
  1009.         { il mattoncino viene rimpiazzato col fondale, tuttavia il fondale }
  1010.         { potrebbe essere inscurito da un ombra proiettata da un altro }
  1011.         { mattoncino }
  1012.  
  1013.         for x:=0 to 15 do
  1014.             if (x+xs)<SCRMAX then
  1015.                begin
  1016.                { calocla l'eventuale ombra proiettata da un altro mattoncino }
  1017.                { shadow:=128 nessuna ombra, shadow:=0 c'e' l'ombra }
  1018.                shadow:=playscreen.map^[x+xs+row[y+ys]] and 128;
  1019.  
  1020.                { prende il pixel di sfondo e ci aggiunge l'ombra se necessario }
  1021.                cl:=(pattern.map^[modx[x+xs]+yh] and 127) or shadow;
  1022.  
  1023.                { dopodiche' mette il colore sia sullo schermo della VGA sia }
  1024.                screen[x+xs+row[y+ys]]:=cl;
  1025.  
  1026.                { sullo schermo ausiliario dove sono presenti solo gli oggetti }
  1027.                { statici e non quelli in movimento tipo pallina o vaus.}
  1028.                playscreen.map^[x+xs+row[y+ys]]:=cl;
  1029.                end;
  1030.         end;
  1031.  
  1032.     { In ogni modo, con il mattoncino deve sparire anche la sua ombra }
  1033.     { l'ombra non e' altro che un rettangolino delle stesse dimensioni del }
  1034.     { mattoncino ma spostato rispetto a questo di 8 pixel sulla asse x, e 4 }
  1035.     { pixel sull'asse y, in altre parole lo spigolo dell'ombra coincide con }
  1036.     { il centro del mattoncino }
  1037.  
  1038.     for y:=ys+4 to ys+12 do
  1039.         for x:=xs+8 to xs+24 do
  1040.  
  1041.             { Occorre controllare che le coordinate non siano superiori a }
  1042.             { quelle del campo di gioco poiche' in tal caso non c'e' nessuna }
  1043.             { ombra da rimuovere poiche' l'ultimo mattoncino proietta un }
  1044.             { ombra parziale che non si riflette sul muro di lato }
  1045.             { Quindi sul muro di lato non c'e' da togliere nessuna ombra }
  1046.  
  1047.             { Lo stesso discorso non viene fatto per il minimo, poiche' }
  1048.             { l'ombra e' sempre piu' a destra e piu' in basso del mattone }
  1049.             { che la proietta, quindi nessun mattoncino puo' proiettare un }
  1050.             { ombra sulla parete di sinistra. Nondimeno nessun mattoncino }
  1051.             { e' talmente basso da proiettare un ombra sul vaus. }
  1052.  
  1053.             { Dunque il caso da tenere in considerazione e' solo x<SCRMAX }
  1054.  
  1055.             if x<SCRMAX then
  1056.                begin
  1057.                { prende il colore di sfondo e toglie l'ombra }
  1058.                cl:=playscreen.map^[x+row[y]] or 128;
  1059.  
  1060.                { e lo memorizza sia sullo schermo fisico ...}
  1061.                screen[x+row[y]]:=cl;
  1062.  
  1063.                { che su quello virtuale (cioe' quello che tiene solo }
  1064.                { gli oggetti fissi }
  1065.                playscreen.map^[x+row[y]]:=cl;
  1066.                end;
  1067.  
  1068.  
  1069.     end;
  1070.  
  1071. procedure place_block(xa,ya,block : integer);
  1072. var
  1073.     x,y,
  1074.     xs,ys : word;
  1075.     cl,cl2: integer;
  1076.     shadow: integer;
  1077.  
  1078.     begin
  1079.     xs:=(xa shl 4)+9;   { calcola le coordinate sullo schermo relativa }
  1080.     ys:=(ya shl 3)+22;  { al mattoncino xa,ya }
  1081.  
  1082.     for y:=0 to 7 do
  1083.         for x:=0 to 15 do
  1084.             begin
  1085.             { controlla se alle coordinate specificate qualche mattoncino }
  1086.             { proietta un ombra }
  1087.             shadow:=playscreen.map^[xs+x+row[ys+y]] and 128;
  1088.  
  1089.             if (y<7) and (x<15) then
  1090.                 begin
  1091.                 { se si tratta dell'interno del mattoncino, lo disegna del }
  1092.                 { colore specificato in block }
  1093.  
  1094.                 cl:=(COLORBLOCK[(block-1) and 15] and 127) or shadow;
  1095.                 screen[xs+x+row[ys+y]]:=cl;
  1096.                 playscreen.map^[xs+x+row[ys+y]]:=cl;
  1097.                 end
  1098.             else
  1099.                begin
  1100.                { nel caso le coordinate si trovino sul bordo destro o }
  1101.                { inferiore, disegna i pixel in nero }
  1102.  
  1103.                screen[xs+x+row[ys+y]]:=shadow; { sarebbe shadow or 0 }
  1104.                playscreen.map^[xs+x+row[ys+y]]:=shadow; {...quindi shadow }
  1105.                end;
  1106.             end;
  1107.  
  1108.     { adesso disegna l'ombra del mattoncino }
  1109.     for y:=ys+4 to ys+12 do
  1110.         for x:=xs+8 to xs+24 do
  1111.             if x<SCRMAX then  { controlla come in remove_block che le coord }
  1112.                               { non siano oltre alla parete di destra, poiche' }
  1113.                               { l'ombra non viene proiettata su tale parete }
  1114.                begin
  1115.                { preleva il pixel x,y dallo schermo e ci proietta sopra }
  1116.                { l'ombra. }
  1117.                cl:=playscreen.map^[x+row[y]] and 127;
  1118.  
  1119.                { dopo di che lo rimette sullo schermo fisico... }
  1120.                screen[x+row[y]]:=cl;
  1121.  
  1122.                { e su quello virtuale }
  1123.                playscreen.map^[x+row[y]]:=cl;
  1124.                end;
  1125.  
  1126.     if block>8 then { ma se il blocco e' grigio (=9) o marrone (=10) ... }
  1127.        begin
  1128.        cl2:=0;
  1129.        if (block and 15)=9 then
  1130.           begin
  1131.           cl2:=202; { il colore del mattoncino e' quello grigio }
  1132.           wall[xa,ya]:=9+(GRAYDOWN shl 4); { e il numero del mattone e 9+16*n }
  1133.           { dove n+1 e' il numero di colpi necessari per abbatterlo }
  1134.           { es. wall[1,2]=9+(1*16)=25 significa che il mattoncino alle }
  1135.           { coord. 1,2 cade se colpito 2 volte }
  1136.           end
  1137.  
  1138.        else if block=10 then cl2:=201;
  1139.        { se il blocco e marrone il colore e' il n.201 }
  1140.  
  1141.        { disegna il bordo superiore del mattoncino }
  1142.        for y:=0 to 6 do
  1143.            begin
  1144.  
  1145.            { preleva il pixel xs,y+ys dallo schermo, ci mette l'ombra }
  1146.            { cioe' fa in modo che il colore sia di tonalita' scura }
  1147.            cl:=playscreen.map^[xs+row[y+ys]] and 128;
  1148.            cl2:=(cl2 and 127) or cl;
  1149.  
  1150.            { ... e lo rimette sullo schermo fisico }
  1151.            screen[xs+row[ys+y]]:=cl2;
  1152.  
  1153.            { ... e su quello virtuale }
  1154.            playscreen.map^[xs+row[ys+y]]:=cl2;
  1155.            end;
  1156.  
  1157.        { disegna il bordo destro del mattoncino }
  1158.        for x:=0 to 14 do
  1159.            begin
  1160.            { commenti analoghi a sopra }
  1161.            cl:=playscreen.map^[xs+x+row[ys]] and 128;
  1162.            cl2:=(cl2 and 127) or cl;
  1163.  
  1164.            screen[xs+x+row[ys]]:=cl2;
  1165.            playscreen.map^[xs+x+row[ys]]:=cl2;
  1166.            end;
  1167.        end;
  1168.     end;
  1169.  
  1170. procedure put_wall;  { mette sullo schermo il muro contenuto in wall[x,y] }
  1171. var
  1172.     x,y : integer;
  1173.  
  1174.     begin
  1175.     for y:=0 to 14 do
  1176.         for x:=0 to 12 do
  1177.             if wall[x,y]<>0 then place_block(x,y,wall[x,y]);
  1178.     end;
  1179.  
  1180. procedure set_wall;             { imposta il muro }
  1181. var x,y,wl  : integer;
  1182.     name    : string;
  1183.  
  1184.     begin
  1185.     remain_blk:=0;                { sono i blocchi da distruggere }
  1186.     wl:=score.wall_n[cur_player]; { questo e' il muro a cui e' fermo il }
  1187.                                   { giocatore cur_player }
  1188.  
  1189.     for y:=0 to 14 do             { conta i blocchi distruttibili }
  1190.         for x:=0 to 12 do         { cioe' il blocco deve essere <>0 e <>10 }
  1191.                                   { poiche' 0 = nessun blocco, 10 = marrone }
  1192.  
  1193.             if (wall[x,y]<>0) and (wall[x,y]<>10) then inc(remain_blk);
  1194.  
  1195.     name:='PATTERN'+chr(48+((wl-1) mod PATNUMBER))+'.BTM';
  1196.     { name e' una stringa che contiene il nome del file di sfondo da caricare }
  1197.  
  1198.     loadBTM(name,pattern,FALSE);
  1199.     if not success then
  1200.        fatal_error('Some Background files seems to be missing');
  1201.  
  1202.     { e quindi carica il file in questione }
  1203.     end;
  1204.  
  1205. { prende in entrata le coordinate di due punti e calcola i punti in cui il }
  1206. { reticolo di mattoncini interseca il segmento congiungente i due punti.   }
  1207.  
  1208. { i punti di intersezione possono essere 1 o 2 }
  1209.  
  1210. function split_line(var x1,y1,x2,y2 : integer) : integer;
  1211. var
  1212.     x,y,
  1213.     xk,yk,
  1214.     xj,yj,
  1215.     xh,yh,
  1216.     xn,yn,
  1217.     xp1,yp1,
  1218.     xp2,yp2,
  1219.     xp,yp,
  1220.     xa,ya,
  1221.     collision : integer;
  1222.  
  1223.     px1,px2,py1,py2 : longint;
  1224.  
  1225.     s1,s : string;
  1226.  
  1227.     begin
  1228.     inc(x1,16);         { incrementa le coordinate di tutti i punti }
  1229.     inc(y1,24);         { per evitare che nel corso delle operazioni }
  1230.     inc(x2,16);         { qualche coordinata diventi negativa }
  1231.     inc(y2,24);         { prima di terminare la proc. li rimette a posto }
  1232.  
  1233.     collision:=0;       { numero di intersezioni fra segmento e reticolo }
  1234.  
  1235.     xp1:=x1 shr 4;      { si calcola all'interno di quale mattoncino stanno }
  1236.     yp1:=y1 shr 3;      { i due punti in questione }
  1237.     xp2:=x2 shr 4;
  1238.     yp2:=y2 shr 3;
  1239.  
  1240.     xk:=x1;             { copia temporaneamente le coord. dei due punti }
  1241.     yk:=y1;             { in due vettori in modo da poter operare liberamente }
  1242.     xj:=x2;             { le coord. iniziali vengono passate per indirizzo }
  1243.     yj:=y2;             { e quindi non devono perdersi i valori }
  1244.  
  1245.     xh:=x1;
  1246.     yh:=y1;
  1247.     xn:=x2;
  1248.     yn:=y2;
  1249.  
  1250.  
  1251.     { Se e' vero questo "if" vuol dire che c'e' un baco nel programma    }
  1252.     { e quindi il gioco quit-ta all'istante segnalando l'errore.         }
  1253.     { Tale errore si verifica facilmente se si pone MAXSPEED >> 2000     }
  1254.  
  1255.     if (abs(x1-x2)>16) or (abs(y2-y1)>8) then
  1256.        fatal_error('Ball speed exceed program capability');
  1257.  
  1258.     if (xp1<>xp2) or (yp1<>yp2) then   { se i due punti non coincidono... }
  1259.        begin
  1260.        if (yp1<>yp2) then    { se i due punti hanno diversa y }
  1261.           begin
  1262.           collision:=collision or 1; { il bit piu' basso viene messo a 1 }
  1263.  
  1264.           while ((yn and 7)<>0) and ((yn and 7)<>7) do
  1265.             begin
  1266.             x:=(xh+xn) shr 1; { dopo di che continua a dividere il segmento }
  1267.             y:=(yh+yn) shr 1; { (x1,y1)-(x2,y2) finche non trova un inter- }
  1268.                               { sezione con un reticolo }
  1269.             yp:=y shr 3;
  1270.  
  1271.             if yp=yp1 then    { dei tre punti (due sono gli estremi del }
  1272.                begin          { segmento) ne scarta uno con lo stesso   }
  1273.                xh:=x;         { principio del teorema di Weierstrass.   }
  1274.                yh:=y;
  1275.                end;
  1276.  
  1277.             if yp=yp2 then    { Il punto di mezzo sostituisce cioe' uno }
  1278.                begin          { dei due estremi in modo che il segmento }
  1279.                xn:=x;         { sia ancora a cavallo del reticolo.      }
  1280.                yn:=y;
  1281.                end;
  1282.             end;
  1283.  
  1284.           end;
  1285.  
  1286.        if (xp1<>xp2) then   { se i due punti hanno diversa coord. x ... }
  1287.           begin
  1288.           collision:=collision or 2; { in questo caso setta il secondo bit }
  1289.  
  1290.           while ((xj and 15)<>0) and ((xj and 15)<>15) do
  1291.             begin
  1292.             x:=(xk+xj) shr 1;    { e i passi sono analoghi per le x }
  1293.             y:=(yk+yj) shr 1;
  1294.  
  1295.             xp:=x shr 4;
  1296.  
  1297.             if xp=xp1 then
  1298.                begin
  1299.                xk:=x;
  1300.                yk:=y;
  1301.                end;
  1302.  
  1303.             if xp=xp2 then
  1304.                begin
  1305.                xj:=x;
  1306.                yj:=y;
  1307.                end;
  1308.  
  1309.             end;
  1310.  
  1311.           end;
  1312.  
  1313.  
  1314.        { vengono ri-assegnati i valori agli estremi a seconda di quali }
  1315.        { porzioni del programma sono state eseguite sopra }
  1316.  
  1317.        if collision=1 then  { ovvero le due x uguali, le due y diverse }
  1318.           begin
  1319.           x2:=xn;
  1320.           y2:=yn;
  1321.           end
  1322.        else if collision=2 then  { le due x diverse, le due y uguali }
  1323.           begin
  1324.           x2:=xj;
  1325.           y2:=yj;
  1326.           end
  1327.        else if collision=3 then  { sia le due x che le due y diverse }
  1328.           begin
  1329.           x1:=xj;         { in questo caso le intersezioni sono 2    }
  1330.           y1:=yj;         { e la procedura li restituisce in (x1,y1) }
  1331.           x2:=xn;         { (x2,y2).                                 }
  1332.           y2:=yn;
  1333.           end;
  1334.  
  1335.        end
  1336.  
  1337.     else fatal_error('Ball seems to be still');
  1338.     { altrimenti qualcosa e' andato storto! }
  1339.  
  1340.     dec(x1,16);   { ripristina le vecchie coordinate }
  1341.     dec(y1,24);
  1342.     dec(x2,16);
  1343.     dec(y2,24);
  1344.  
  1345.  
  1346.     x1:=min(207,max(0,x1));
  1347.     x2:=min(207,max(0,x2));
  1348.  
  1349.     { per la y non vengono tagliate le coordinate <0 e >120 poiche' la   }
  1350.     { matrice che li contiene e' virtualmente piu' lunga per ragioni di  }
  1351.     { sicurezza e per coord. non valide non si trova alcun mattoncino da }
  1352.     { urtare. Il clipping in questo caso e' piu' semplice.               }
  1353.  
  1354.     split_line:=collision;
  1355.     end;
  1356.  
  1357. { Considera colpito il blocco xb,yb: se e' un blocco normale lo toglie,
  1358.   se e' un grigio che resiste a piu' colpi ne decrementa la resistenza.
  1359.   Se il blocco non viene abbattuto allora lo fa luccicare. }
  1360.  
  1361. procedure shoot_block(xb,yb : integer; var ball : BALLTYPE);
  1362.  
  1363.     begin
  1364.     { Controlla che le coordinate del blocco siano numeri validi... }
  1365.     if (xb>=0) and (xb<=12) and (yb>=0) and (yb<=14) then
  1366.        begin
  1367.        if wall[xb,yb]<>0 then { ... che ci sia un blocco da colpire... }
  1368.           begin
  1369.           if wall[xb,yb]<10 then { se il blocco puo' essere abbattuto... }
  1370.              begin
  1371.              remove_block(xb,yb); { ..lo toglie dallo schermo }
  1372.              dec(remain_blk);     { ..decrementa il numero di blocchi che restano }
  1373.  
  1374.              { Incrementa lo SCORE del giocatore attuale a seconda }
  1375.              { del blocco colpito (i punti sono nell'array in SCORE_WALL) }
  1376.              inc(score.player[cur_player],SCORE_WALL[wall[xb,yb]]);
  1377.  
  1378.              inc(lett.incoming,random(LETTER_PROB));
  1379.  
  1380.              with lett do
  1381.                   begin
  1382.                   nextx:=(xb shl 4)+9;
  1383.                   nexty:=((yb+1) shl 3)+22;
  1384.                   nexttype:=random_letter_drop;
  1385.                   end;
  1386.  
  1387.              wall[xb,yb]:=0;          { il blocco viene cancellato        }
  1388.              ball_block_sound(440,3); { emette un LA (nota musicale)      }
  1389.              ball.sbd:=0;             { azzera il contatore di deviazione }
  1390.              ball.brwhit:=0;          { e il cont. di dev. di emergenza   }
  1391.              end
  1392.  
  1393.           else    { se il blocco e marrone, o un grigio che non cade subito }
  1394.              begin
  1395.              if (wall[xb,yb] and 15)=9 then { ...se e' grigio... }
  1396.                 begin
  1397.                 ball.brwhit:=0;      { azzera il cont. di dev. di emergenza }
  1398.                 dec(wall[xb,yb],16); { decrementa la resistenza del blocco  }
  1399.  
  1400.                 ball_block_sound(370,4);{ Emette un Fa# (nota musicale)    }
  1401.                 shine(xb,yb);           { e imposta il luccichio del blocco }
  1402.                 end
  1403.              else
  1404.                 begin
  1405.                 inc(ball.brwhit); { incrementa il cont. di dev. di emergenza }
  1406.                 shine(xb,yb);     { imposta il luccichio }
  1407.  
  1408.                 ball_block_sound(200,7); { ed emette una nota piuttosto bassa }
  1409.                 end;
  1410.              end;
  1411.           end;
  1412.        end;
  1413.     end;
  1414.  
  1415. { Simile a quella prima ma per la collisione fire_blocco }
  1416. procedure shoot_block_with_fire(xb,yb : integer);
  1417.  
  1418.     begin
  1419.     if (xb>=0) and (xb<=12) and (yb>=0) and (yb<=14) then
  1420.        begin
  1421.        if wall[xb,yb]<>0 then { ... che ci sia un blocco da colpire... }
  1422.           begin
  1423.           if wall[xb,yb]<10 then { se il blocco puo' essere abbattuto... }
  1424.              begin
  1425.              remove_block(xb,yb); { ..lo toglie dallo schermo }
  1426.              dec(remain_blk);     { ..decrementa il numero di blocchi che restano }
  1427.              inc(score.player[cur_player],SCORE_WALL[wall[xb,yb]]);
  1428.              wall[xb,yb]:=0;          { il blocco viene cancellato        }
  1429.              ball_block_sound(440,3); { emette un LA (nota musicale)      }
  1430.              end
  1431.  
  1432.           else    { se il blocco e marrone, o un grigio che non cade subito }
  1433.              begin
  1434.              if (wall[xb,yb] and 15)=9 then { ...se e' grigio... }
  1435.                 begin
  1436.                 dec(wall[xb,yb],16); { decrementa la resistenza del blocco  }
  1437.                 ball_block_sound(370,4);{ Emette un Fa# (nota musicale)    }
  1438.                 shine(xb,yb);           { e imposta il luccichio del blocco }
  1439.                 end
  1440.              else
  1441.                 begin
  1442.                 shine(xb,yb);     { imposta il luccichio }
  1443.                 ball_block_sound(200,7); { ed emette una nota piuttosto bassa }
  1444.                 end;
  1445.              end;
  1446.           end;
  1447.        end;
  1448.     end;
  1449.  
  1450.  
  1451. procedure ball_hit_block(var ball : BALLTYPE);
  1452. var x,y,z    : integer;
  1453.     xb,yb    : integer;
  1454.     x1,y1    : array[0..4] of integer;
  1455.     a,b,
  1456.     ox,oy,
  1457.     lx,ly,
  1458.     mx,my,
  1459.     nx,ny,
  1460.     f1,f2,
  1461.     collision: integer;
  1462.     betaflag : boolean;
  1463.     touch    : integer;
  1464.     adjw     : array[0..2,0..2] of integer;
  1465.     deflect,
  1466.     around,
  1467.     emergency,
  1468.     mimax,
  1469.     angle,
  1470.     myx,myy  : integer;
  1471.  
  1472.     begin
  1473.     emergency:=EMP;    { l'indicatore di rimbalzo di emergenza }
  1474.  
  1475.     nx:=ball.x-9;      { nx,ny hanno le coordinate della palla rispetto }
  1476.     ny:=ball.y-22;     { all'origine fissata nell'angolo Nord-Ovest del }
  1477.                        { campo di gioco (entro cui si muove la palla).  }
  1478.  
  1479.     ox:=ball.oldx-9;   { idem per le vecchie coordinate, l'origine e'   }
  1480.     oy:=ball.oldy-22;  { quindi il punto dello schermo (9,22).          }
  1481.  
  1482.     xb:=nx shr 4;     { xb,yb sono le coordinate del blocco (eventualmente  }
  1483.     yb:=ny shr 3;     { ipotetico) su cui si trova ora la pallina.          }
  1484.                       { Ricordarsi che (0,0) e' il blocco in altro a destra }
  1485.  
  1486.     if wall[xb,yb]<>0 then  { ...se il blocco non e' ipotetico ma esiste }
  1487.        begin
  1488.        collision:=split_line(ox,oy,nx,ny);
  1489.        { calcola l'intersezione del segmento che unisce le vecchie alle    }
  1490.        { nuove coordinate. "Collision" contiene un valore che dipende dal  }
  1491.        { tipo di intersezioni riscontrate fra il segmento e la griglia dei }
  1492.        { blocchi.                                                          }
  1493.  
  1494.        if collision=3 then     { se sono avvenute due collisioni... }
  1495.           begin
  1496.           lx:=ball.oldx-ox-9;  { si calcola la distanza della vecchia }
  1497.           ly:=ball.oldy-oy-22; { coordinata dal punto di intersezione 1 }
  1498.  
  1499.           mx:=ball.oldx-nx-9;  { e dal punto di intersezione 2 }
  1500.           my:=ball.oldy-ny-22;
  1501.  
  1502.           f1:=lx*lx+ly*ly;     { indi sceglie fra i due il punto di }
  1503.           f2:=mx*mx+my*my;     { intersezione piu' vicino alle vecchie coord. }
  1504.  
  1505.           if (f1<f2) then      { f1 e f2 sono il quadrato del modulo del }
  1506.                                { vettore distanza (vedi sopra) }
  1507.  
  1508.              { Si considera il caso in cui l'intersezione piu' vicina sia }
  1509.              { la numero 1. }
  1510.  
  1511.              begin
  1512.              xb:=min(12,max(ox shr 4,0));  { Vengono assegnate le coord. }
  1513.              yb:=((oy+24) shr 3)-3;        { del blocco relative a tale  }
  1514.                                            { intersezione.               }
  1515.  
  1516.              if wall[xb,yb]=0 then         { Se non vi e' alcun blocco   }
  1517.                 begin
  1518.                 xb:=min(12,max(0,nx shr 4)); { Allora l'urto avviene sull' }
  1519.                 yb:=((ny+24) shr 3)-3;       { altra intersezione. La n.2  }
  1520.                 end
  1521.              else
  1522.                 begin                        { Se invece il blocco esiste  }
  1523.                 nx:=ox;                      { allora alle nuove coord. si }
  1524.                 ny:=oy;                      { assegna il punto di inter-  }
  1525.                                              { sezione contenuto nelle vec-}
  1526.                                              { chie.                       }
  1527.                 end;
  1528.              end
  1529.           else
  1530.              begin
  1531.              { Nel caso sia la seconda intersezione piu' vicina alle }
  1532.              { vecchie coord. si procede analogamente.               }
  1533.  
  1534.              xb:=min(12,max(0,nx shr 4)); { Si calcolano le coord. del blocco }
  1535.              yb:=((ny+24) shr 3)-3;       { sull'intersezione nx,ny (la seconda) }
  1536.  
  1537.              if wall[xb,yb]=0 then        { Se il blocco non c'e'... }
  1538.                 begin
  1539.                 nx:=ox;                   { allora l'intersezione valida e' }
  1540.                 ny:=oy;                   { l'altra, e si procede... }
  1541.  
  1542.                 xb:=min(12,max(0,nx shr 4)); { ...riassegnando alle nuove }
  1543.                 yb:=((ny+24) shr 3)-3;       { coord. l'intersezione n.1  }
  1544.                 end;
  1545.              end;
  1546.  
  1547.           end;
  1548.  
  1549.        ball.x:=nx+9;    { Le nuove coordinate della palla sono quelle      }
  1550.        ball.y:=ny+22;   { contentenute nelle variabili nx,ny, ritraslando  }
  1551.                         { gli assi. nx,ny avevano i relativi assi centrati }
  1552.                         { in (9,22).                                       }
  1553.  
  1554.        shoot_block(xb,yb,ball);  { abbatte il blocco in questione }
  1555.  
  1556.        x:=(nx and 15) shr 1;     { si calcola il punto d'urto della palla }
  1557.        y:=(ny and 7);            { rispetto al mattoncino.                }
  1558.  
  1559.        { Dividendo per 2 la coord. x dell'urto si ottiene una sezione d'urto }
  1560.        { su di un mattone quadrato invece che rettangolare che semplifica in }
  1561.        { seguito i calcoli. Il mattone e' infatti di 16x8 pixel dividendo    }
  1562.        { per 2 diventa di 8x8 pixel, e i calcoli sulle diagonali sono piu'   }
  1563.        { semplici. }
  1564.  
  1565.  
  1566.        { Se l'urto non avviene su uno dei bordi del mattone allora vuole }
  1567.        { dire che qualcosa e' andato storto. In teoria non dovrebbe mai  }
  1568.        { verificarsi.                                                    }
  1569.        if (x<>0) and (x<>7) and (y<>0) and (y<>7) then
  1570.           fatal_error('Ball hit a block not on its surface');
  1571.  
  1572.  
  1573.        { Questi sono i valori che assume EMERGENCY a seconda del punto d'urto }
  1574.  
  1575.        {                     5     1     8                               }
  1576.        {                      -----------                                }
  1577.        {                    2 | mattone | 4                              }
  1578.        {                      -----------                                }
  1579.        {                     6     3     7                               }
  1580.  
  1581.  
  1582.  
  1583.        { Se la palla urta il bordo superiore del mattoncino... }
  1584.  
  1585.        if (y<x) and (x<7-y) then
  1586.           begin
  1587.           ball.speedy:=-ball.speedy;   { Si inverte la coord. y della vel. }
  1588.           emergency:=1;                { e segna l'eventiale punto di contatto }
  1589.           end;
  1590.  
  1591.        { ...il bordo inferiore... }
  1592.        if (7-y<x) and (x<y) then
  1593.           begin
  1594.           ball.speedy:=-ball.speedy;   { inverte la y della vel. }
  1595.           emergency:=3;
  1596.           end;
  1597.  
  1598.        { ...il bordo sinistro... }
  1599.        if (x<y) and (y<7-x) then
  1600.           begin
  1601.           ball.speedx:=-ball.speedx;   { inverte la x della vel. }
  1602.           emergency:=2;
  1603.           end;
  1604.  
  1605.        { ... e quello destro ... }
  1606.        if (7-x<y) and (y<x) then
  1607.           begin
  1608.           ball.speedx:=-ball.speedx;   { inverte la x della vel. }
  1609.           emergency:=4;
  1610.           end;
  1611.  
  1612.        { ... se invece avviene su uno dei quattro spigoli ... }
  1613.        if (x=y) or (x=7-y) then
  1614.           begin
  1615.           deflect:=$00;
  1616.           touch:=0;
  1617.  
  1618.           { touch assume valori diversi a seconda dello spigolo         }
  1619.           { Segue la tabella (per es. 0 = angolo in alto a sinistra)    }
  1620.  
  1621.           { 0 1 }
  1622.           { 2 3 }
  1623.  
  1624.           if x>4 then touch:=touch or 1;
  1625.           if y>4 then touch:=touch or 2;
  1626.  
  1627.  
  1628.           { Qui riempie una matrice 3x3 con degli 1 o degli 0 a seconda che }
  1629.           { attorno al blocco urtato rispettivamente vi siano o no altri    }
  1630.           { mattoncini }
  1631.  
  1632.           { I bordi sinistro e destro del campo di gioco vengono considerati }
  1633.           { come mattoncini indistruttibili in questo caso.                  }
  1634.  
  1635.           for lx:=-1 to 1 do
  1636.               for ly:=-1 to 1 do
  1637.                   begin
  1638.                   mx:=max(min(xb+lx,12),0); { quando si fa rif. alla x la }
  1639.                   my:=yb+ly;                { coord deve essere compresa  }
  1640.                                             { fra 0 e 12.                 }
  1641.  
  1642.                   if ((xb+lx)<0 ) or
  1643.                      ((xb+lx)>12) or
  1644.                      (wall[mx,my]<>0) then
  1645.                         adjw[lx+1,ly+1]:=1   { Vi sono mattoncini }
  1646.                   else
  1647.                      adjw[lx+1,ly+1]:=0;     { Non vi sono mattoncini }
  1648.  
  1649.                   end;
  1650.  
  1651.           { Around contiene un valore che in binario rappresenta lo stato }
  1652.           { dei mattoncini che stanno attorno al mattone urtato.          }
  1653.  
  1654.           {        -------------                      }
  1655.           {        | 1 | 2 | 4 |                      }
  1656.           {        -------------                      }
  1657.           {        |128| U | 8 |   U = mattone urtato }
  1658.           {        -------------                      }
  1659.           {        | 64| 32| 16|                      }
  1660.           {        -------------                      }
  1661.  
  1662.           { Es. se attorno ad U si trovano i mattoncini 1,2,128 il valore }
  1663.           { di around e' 1+2+128=131.                                     }
  1664.  
  1665.           around:=adjw[0,0]+(adjw[1,0] shl 1)+
  1666.                             (adjw[2,0] shl 2)+(adjw[2,1] shl 3)+
  1667.                             (adjw[2,2] shl 4)+(adjw[1,2] shl 5)+
  1668.                             (adjw[0,2] shl 6)+(adjw[0,1] shl 7);
  1669.  
  1670.           { Deflect contiene un valore che in esadecimale rappresenta le }
  1671.           { modifiche da apportare alla vx (prima cifra esadec.) e alla  }
  1672.           { y (seconda cifra esadec.). Secondo la seguente tabella.      }
  1673.  
  1674.           { 0 = coordinata inalterata }
  1675.           { 1 =     ''     negativa   }
  1676.           { 2 =     ''     positiva   }
  1677.           { 3 =     ''     invertita  }
  1678.  
  1679.           { Es. Deflect:=$13 significa poni vx negativo e inverti vy }
  1680.           {     Deflect:=$20 significa poni vx positivo e lascia stare vy }
  1681.  
  1682.           { ------------------------------------------------------------- }
  1683.  
  1684.           { Seguono le combinazioni caso per caso dello spigolo urtato, dei   }
  1685.           { mattoni che questo a attorno e di conseguenza ricava la direzione }
  1686.           { della palla.                                                      }
  1687.  
  1688.           { l'and logico significa considera solo i mattoni la cui somma }
  1689.           { da il numero che segue. }
  1690.  
  1691.           { Per es. "and 131" significa considera solo i mattoni 1+2+128 }
  1692.           { gli altri se ci sono o no non importa.        }
  1693.  
  1694.           if touch=0 then       { spigolo in alto a sinistra }
  1695.              begin
  1696.              if (around and 131)=0   then deflect:=$11;
  1697.              if (around and 131)=1   then deflect:=$33;
  1698.              if (around and 131)=2   then deflect:=$10;
  1699.              if (around and 131)=3   then deflect:=$12;
  1700.              if (around and 131)=128 then deflect:=$01;
  1701.              if (around and 131)=129 then deflect:=$21;
  1702.              if (around and 131)=130 then deflect:=$11;
  1703.  
  1704.              emergency:=5;
  1705.              shoot_block(xb-1,yb-1,ball);
  1706.              end;
  1707.  
  1708.           { "and 14" sono i mattoni 2+4+8, gli altri non importa }
  1709.  
  1710.           if touch=1 then       { spigolo in altro a destra  }
  1711.              begin
  1712.              if (around and 14)=0    then deflect:=$21;
  1713.              if (around and 14)=2    then deflect:=$20;
  1714.              if (around and 14)=4    then deflect:=$33;
  1715.              if (around and 14)=6    then deflect:=$22;
  1716.              if (around and 14)=8    then deflect:=$01;
  1717.              if (around and 14)=10   then deflect:=$21;
  1718.              if (around and 14)=12   then deflect:=$11;
  1719.  
  1720.              emergency:=8;
  1721.              shoot_block(xb+1,yb-1,ball);
  1722.              end;
  1723.  
  1724.           if touch=2 then       { Spigolo in basso a sinistra }
  1725.              begin
  1726.              if (around and 224)=0    then deflect:=$12;
  1727.              if (around and 224)=32   then deflect:=$10;
  1728.              if (around and 224)=64   then deflect:=$33;
  1729.              if (around and 224)=96   then deflect:=$11;
  1730.              if (around and 224)=128  then deflect:=$02;
  1731.              if (around and 224)=160  then deflect:=$12;
  1732.              if (around and 224)=192  then deflect:=$22;
  1733.  
  1734.              emergency:=6;
  1735.              shoot_block(xb-1,yb+1,ball);
  1736.              end;
  1737.  
  1738.           if touch=3 then       { Spigolo in basso a destra   }
  1739.              begin
  1740.              if (around and 56)=0    then deflect:=$22;
  1741.              if (around and 56)=8    then deflect:=$02;
  1742.              if (around and 56)=16   then deflect:=$33;
  1743.              if (around and 56)=24   then deflect:=$12;
  1744.              if (around and 56)=32   then deflect:=$20;
  1745.              if (around and 56)=40   then deflect:=$22;
  1746.              if (around and 56)=48   then deflect:=$21;
  1747.  
  1748.              emergency:=7;
  1749.              shoot_block(xb+1,yb+1,ball);
  1750.              end;
  1751.  
  1752.           { La prima cifra hex (esadecimale) viene messa in myx }
  1753.           { e la seconda in myy. }
  1754.  
  1755.           myx:=deflect shr 4;
  1756.           myy:=deflect and 15;
  1757.  
  1758.           if myx=1 then ball.speedx:=-abs(ball.speedx);
  1759.           if myx=2 then ball.speedx:= abs(ball.speedx);
  1760.           if myx=3 then ball.speedx:=-    ball.speedx ;
  1761.  
  1762.           if myy=1 then ball.speedy:=-abs(ball.speedy);
  1763.           if myy=2 then ball.speedy:= abs(ball.speedy);
  1764.           if myy=3 then ball.speedy:=-    ball.speedy ;
  1765.  
  1766.           end;
  1767.  
  1768.        end;
  1769.  
  1770.  
  1771.     { Nel caso che il numero di mattoni indistruttibili urtati consecutivamente }
  1772.     { prima di urtare un mattone di un altro tipo superi una determinata soglia }
  1773.  
  1774.     if ball.brwhit>MAXBRWHIT then
  1775.        begin
  1776.        { Se emergency e' rimasto a EMP significa che qualcosa e' andato storto }
  1777.        if emergency=EMP then fatal_error('No collisions detected');
  1778.  
  1779.        mimax:=EMERG_DEV[emergency]; { Altrimenti si calcola la deviazione }
  1780.                                     { massima e minima del mattoncino.    }
  1781.  
  1782.        { e a seconda di quale spigolo viene urtato e di come sono i mattoni }
  1783.        { attorno a tale spigolo, la deviazione viene modificata. }
  1784.  
  1785.        { Per quanto il rimbalzo finale possa essere strano, questo controllo }
  1786.        { viene fatto per evitare che la palla si incastri in un loop infinito }
  1787.  
  1788.        { ovviamente il caso vale per i mattoni indistruttibili perche' gli }
  1789.        { altri prima o poi cadono e quindi non possono bloccare la palla   }
  1790.        { per un tempo infinito.                                            }
  1791.  
  1792.        { Ogni cifra hex di mimax esprime un angolo a multipli di 90 gradi  }
  1793.        { la prima cifra e' l'angolo minimo, la seconda quello massimo.     }
  1794.  
  1795.        { Es. MIMAX:=$03; singifica angolo minimo 0*90 = 0 gradi, angolo max }
  1796.        { 3*90 = 270 gradi, e cosi' via...                                   }
  1797.  
  1798.        { una scrittura del tipo "mimax:=mimax and $0f or 10" significa }
  1799.        { metti a 1 la prima cifra di mimax indipendentemente da quanto }
  1800.        { vale adesso, lasciando inalterata la seconda.                 }
  1801.  
  1802.        { Analogo il ragionamento per "... and $f0 or $03" che agisce   }
  1803.        { sulla seconda cifra invece che sulla prima...                 }
  1804.  
  1805.        case emergency of
  1806.  
  1807.          5: begin
  1808.             if adjw[1,0]=0 then mimax:=mimax and $0f or $00;
  1809.             if adjw[0,1]=0 then mimax:=mimax and $f0 or $03;
  1810.             end;
  1811.  
  1812.          6: begin
  1813.             if adjw[0,1]=0 then mimax:=mimax and $0f or $10;
  1814.             if adjw[1,2]=0 then mimax:=mimax and $f0 or $04;
  1815.             end;
  1816.  
  1817.          7: begin
  1818.             if adjw[1,2]=0 then mimax:=mimax and $0f or $20;
  1819.             if adjw[2,1]=0 then mimax:=mimax and $f0 or $05;
  1820.             end;
  1821.  
  1822.          8: begin
  1823.             if adjw[2,1]=0 then mimax:=mimax and $0f or $30;
  1824.             if adjw[1,0]=0 then mimax:=mimax and $f0 or $06;
  1825.             end;
  1826.  
  1827.          end;
  1828.  
  1829.        repeat
  1830.  
  1831.           lx:=90*(mimax shr 4);    { la prima cifra di mimax viene posta in }
  1832.           mx:=90*(mimax and 15);   { lx e la seconda in mx.                 }
  1833.           angle:=random(mx-lx)+lx; { L'angolo e' una variabile casuale fra  }
  1834.                                    { lx e mx }
  1835.  
  1836.        until ((angle mod 90)>30) and ((angle mod 90)<60);
  1837.        { e questo ciclo si ripete finche' la palla ha un inclinazione }
  1838.        { compresa fra i 30 e i 60 gradi piu' multipli di 90 gradi.    }
  1839.  
  1840.        set_ball_direction(ball,angle mod 360);
  1841.        set_ball_speed(ball,ball.speed);
  1842.  
  1843.        ball.brwhit:=0; { Azzera il contatore di emergenza }
  1844.        end;
  1845.  
  1846.     end;
  1847.  
  1848.  
  1849. { Disegna il fondale sul terreno di gioco }
  1850. procedure fill_picture_with_pattern(var patt : BTMTYPE);
  1851. var x,y,
  1852.     cl,
  1853.     shadow,
  1854.     yb      : integer;
  1855.  
  1856.     begin
  1857.     { Si calcola a priori tutti i valori di x mod patt.width }
  1858.     { patt.width = larghezza del quadrattino che definisce lo sfondo }
  1859.  
  1860.     for x:=0 to 319 do
  1861.         modx[x]:=x mod patt.width;
  1862.  
  1863.     { analogamente per y mod patt.height }
  1864.  
  1865.     for y:=0 to 199 do
  1866.         mody[y]:=y mod patt.height;
  1867.  
  1868.     { Esegue il ciclo principale e il ciclo secondario che riempiono lo }
  1869.     { schermo con tanti quadretti di sfondo quanti sono necessari }
  1870.  
  1871.     for y:=SCRTOP-2 to SCRBOT-2 do
  1872.         begin
  1873.         yb:=mody[y]*patt.width;
  1874.         for x:=SCRMIN-1 to SCRMAX-1 do
  1875.             begin
  1876.             cl:=patt.map^[modx[x]+yb]; { Prende il pixel dallo sfondo }
  1877.             shadow:=128;               { Shadow = 128 -> ombra non presente }
  1878.  
  1879.             { Fa l'ombra sul fianco sinistro e superiore dello schermo  }
  1880.             { E' l'ombra proiettata dal bordo metallico sullo sfondo di }
  1881.             { gioco.                                                    }
  1882.             if (y<16) or (x<18) then shadow:=0; { Shadow=0 -> ombra presente }
  1883.  
  1884.             { Disegna il pixel sullo schermo con l'eventuale ombra }
  1885.             playscreen.map^[x+row[y]]:=(cl and 127) or shadow;
  1886.             end;
  1887.         end;
  1888.  
  1889.     end;
  1890.  
  1891. { Carica tutti i muri contenuti nel file WHWALLS.BTM }
  1892. procedure load_all_walls;
  1893. var
  1894.     s    : string;
  1895.     f1   : text;
  1896.     x,
  1897.     y,
  1898.     z,
  1899.     w    : integer;
  1900.     loop : boolean;
  1901.  
  1902.     begin
  1903.     loop:=TRUE;
  1904.     assign(f1,'whwalls.dta');    { Apre il file }
  1905.     reset(f1);                   { si porta all'inizio dello stesso }
  1906.  
  1907.     x:=0;  { coordinata x del mattoncino attuale-3 }
  1908.     y:=0;  { coordinata y del mattoncino attuale }
  1909.     z:=0;  { numero del muro attuale-1 }
  1910.  
  1911.     while(loop) do
  1912.        begin
  1913.        s:='                                      ';
  1914.        readln(f1,s);
  1915.        if s[1]='*' then { Se il primo carattere della riga e' un asterisco }
  1916.           begin
  1917.           if (y>14) then fatal_error('Too many blocks');
  1918.  
  1919.           for x:=3 to 15 do    { Allora dal terzo al 15 vi sono i 13 blocchi }
  1920.               begin            { che costituiscono la fila }
  1921.               w:=ord(s[x])-96; { Se e' un "a" (codice 97) allora w:=1 }
  1922.               if w<0 then w:=0;
  1923.               all_walls[z][x-3,y]:=w;  { Quindi all_walls contiene tutti }
  1924.               end;                     { i muri. z=numerod del muro.     }
  1925.  
  1926.           inc(y); { Passa alla fila successiva }
  1927.  
  1928.           for x:=0 to 12 do           { Le due file estreme sono sempre vuote }
  1929.               begin                   { vale a dire [x,-1] e [x,15]           }
  1930.               all_walls[z][x,-1]:=0;
  1931.               all_walls[z][x,15]:=0;
  1932.               end;
  1933.           end
  1934.  
  1935.        else if s[1]=';' then   { Il ";" indica che si intende passare al }
  1936.           begin                { prossimo muro. }
  1937.           x:=0;
  1938.           y:=0;
  1939.  
  1940.           if (z>32) then fatal_error('Too many walls');
  1941.           inc(z);
  1942.           end
  1943.        else if s[1]='/' then loop:=false;
  1944.        { lo slash indica la fine logica del file, tutto cio' che segue }
  1945.        { viene ignorato.                                               }
  1946.  
  1947.        { Qualunque riga incominci con un carattere diverso da ";" "*" "/"  }
  1948.        { viene considerata una linea di commento e viene pertanto ignorata }
  1949.  
  1950.        end;
  1951.  
  1952.      close(f1);
  1953.      totalwall:=z;
  1954.      end;
  1955.  
  1956. procedure write_round_level;
  1957. var x,y : integer;            { Stampa la scritta ROUND xx, READY.        }
  1958.     s,r,                      { eventualmente anche il nome del giocatore }
  1959.     sc  : string[20];         { cioe' PLAYER ONE o PLAYER TWO.            }
  1960.  
  1961.     begin
  1962.     settextstyle(DefaultFont,HorizDir,1);
  1963.     str(score.wall_n[cur_player]:2,s);
  1964.     r:='Round '+s;
  1965.     sc:='';
  1966.     if score.pl_numb=2 then   { Nel caso di 2 giocatori, occorre anche }
  1967.        begin                                       { dire a chi tocca. }
  1968.        if cur_player=1 then sc:='Player One'
  1969.        else sc:='Player Two';
  1970.        end;
  1971.  
  1972.     setcolor(0);                            { Stampa le scritte in nero }
  1973.     for x:=0 to 2 do                        { come contorno spostandole }
  1974.         for y:=0 to 2 do                    { di una coordinata in tutte }
  1975.             begin                           { le direzioni.              }
  1976.             outtextxy(72+x,129+y,sc);
  1977.             outtextxy(80+x,139+y,r);
  1978.             outtextxy(90+x,149+y,'Ready');
  1979.             end;
  1980.  
  1981.     setcolor(1);                  { E poi centrata, in bianco stampa }
  1982.     outtextxy(73,130,sc);         { la scritta vera e propria.       }
  1983.     outtextxy(81,140,r);
  1984.     outtextxy(91,150,'Ready');
  1985.     end;
  1986.  
  1987. procedure remove_round_level;  { Togli la scritta ROUND xx, READY }
  1988. var x,y : word;                { copiandoci sopra il fondale.     }
  1989.     begin
  1990.     for y:=129 to 160 do
  1991.         memcpy(addr(playscreen.map^[72+row[y]]),
  1992.                addr(screen[72+row[y]]),88);
  1993.     end;
  1994.  
  1995.  
  1996. { Stampa la scitta GAME OVER }
  1997. procedure Game_over;
  1998. var x,y : integer;
  1999.     sc  : string[20];
  2000.  
  2001.     begin
  2002.     settextstyle(DefaultFont,HorizDir,1);  { Setta la font di default }
  2003.  
  2004.     sc:='';
  2005.     if score.pl_numb=2 then                  { Se vi sono 2 giocatori  }
  2006.        begin                                 { deve dire quale dei due }
  2007.        if cur_player=1 then sc:='Player One' { ha finito.              }
  2008.        else sc:='Player Two';                { E mette in sc "PLAYER ... " }
  2009.        end;                                  { altrimenti sc rimane vuoto  }
  2010.  
  2011.     setcolor(0);
  2012.     for x:=0 to 2 do
  2013.         for y:=0 to 2 do
  2014.             begin                                { Disegna la scritta in    }
  2015.             outtextxy(72+x,129+y,sc);            { nero spostata di una     }
  2016.             outtextxy(76+x,139+y,'Game Over');   { coord. in tutte le direz.}
  2017.             end;
  2018.  
  2019.     setcolor(1);                    { E poi al centro delle scritte in nero }
  2020.     outtextxy(73,130,sc);           { stampa quella in bianco.              }
  2021.     outtextxy(77,140,'Game Over');
  2022.  
  2023.     mydelay(500);
  2024.     remove_round_level; { in questo caso rimuove la scritta GAME OVER }
  2025.                         { invece della scritta ROUND xx, READY.       }
  2026.     end;
  2027.  
  2028.  
  2029. { Mostra in sequenza i fotogrammi del vaus che si distrugge. }
  2030. procedure destroy_vaus;
  2031. var x,y,z,w : word;
  2032.     a,b     : word;
  2033.  
  2034.     begin
  2035.     playvaus:=normal;
  2036.     modify_vaus;
  2037.  
  2038.     move_vaus(vaus.x,vaus.y);
  2039.  
  2040.     a:=vaus.x-4;     { Si calcola uno spostamento dovuto al brush  }
  2041.     b:=vaus.y-5;     { dell'animazione che e' leggermente spostato }
  2042.                      { dall'origine degli assi.                    }
  2043.  
  2044.     for w:=0 to 6 do  { w = fotogramma da mostrare, li cicla tutti da 0 a 6 }
  2045.         begin
  2046.         for y:=0 to 15 do
  2047.             begin
  2048.             z:=y*explosion.width+w*(explosion.width shl 4);
  2049.             for x:=0 to explosion.width-1 do
  2050.                 begin
  2051.                 { Se il colore e' trasparente o il fotogramma e' il 6 }
  2052.                 { allora viene usato il colore del fondale.           }
  2053.                 if (w=6) or (explosion.map^[x+z]=0) then
  2054.                    screen[x+a+row[y+b]]:=playscreen.map^[x+a+row[y+b]]
  2055.                 else
  2056.                    screen[x+a+row[y+b]]:=explosion.map^[x+z];
  2057.                 end;
  2058.             end;
  2059.  
  2060.         death_sound(w);   { Il cicalino di quando il vaus viene distrutto }
  2061.                           { per ogni valore di w c'e' una nota diversa    }
  2062.         end;
  2063.  
  2064.     death_sound(7);
  2065.     mydelay(150);         { attende qualche istante. }
  2066.     disable_letter;       { se nel frattempo stava scendendo una lettera, }
  2067.                           { la toglie.                                    }
  2068.     end;
  2069.  
  2070. { E' esattamente come quella di prima, soltanto che mostra l'animazione }
  2071. { del vaus che si costruisce.                                           }
  2072. procedure create_vaus;
  2073. var x,y,z,w : word;
  2074.     a,b     : word;
  2075.  
  2076.     begin
  2077.     nosound;
  2078.     a:=((SCRMAX-SCRMIN) div 2)-12;
  2079.     b:=vaus_line-5;
  2080.  
  2081.     for w:=11 downto 0 do
  2082.         begin
  2083.         for y:=0 to 15 do
  2084.             begin
  2085.             z:=y*newvaus.width+w*(newvaus.width*16);
  2086.             for x:=0 to newvaus.width-1 do
  2087.                 begin
  2088.                 if (newvaus.map^[x+z]=0) then
  2089.                    screen[x+a+row[y+b]]:=playscreen.map^[x+a+row[y+b]]
  2090.                 else
  2091.                    screen[x+a+row[y+b]]:=newvaus.map^[x+z];
  2092.                 end;
  2093.             end;
  2094.  
  2095.         mydelay(1);
  2096.         end;
  2097.     end;
  2098.  
  2099. procedure put_digit(px,py,num : word);  { Stampa la cifra digitale num }
  2100.                                         { alle coord. px,py.           }
  2101. var x,y,a : word;
  2102.  
  2103.     begin
  2104.     a:=222; { Il colore 222 e' il rosso scuro che viene usato se il led }
  2105.             { in questione deve apparire spento.                        }
  2106.             { Mentre il colore 223 e' il rosso vivo di quando il led e' }
  2107.             { acceso.                                                   }
  2108.  
  2109.     { ----------------- }
  2110.     { |       0       | }
  2111.     { ----------------- }
  2112.     { |   |       |   | }
  2113.     { | 3 |       | 5 | }
  2114.     { |   |       |   | }
  2115.     { |   |       |   | }
  2116.     { ----------------- }
  2117.     { |       1       | }
  2118.     { ----------------- }
  2119.     { |   |       |   | }
  2120.     { | 4 |       | 6 | }
  2121.     { |   |       |   | }
  2122.     { |   |       |   | }
  2123.     { ----------------- }
  2124.     { |       2       | }
  2125.     { ----------------- }
  2126.  
  2127.     { Bit 0 }
  2128.     if (DIGITS[num] and 1)=1 then a:=223;   { Se il bit 0 e' 1 allora    }
  2129.     for x:=1 to 4 do                        { il colore del led in altro }
  2130.         screen[px+x+row[py]]:=a;            { e' rosso vivo, altrimenti  }
  2131.                                             { rosso scuro.               }
  2132.  
  2133.     { Bit 1 }
  2134.     a:=222;                             { "a" viene assunto come rosso scuro }
  2135.     if (DIGITS[num] and 2)=2 then a:=223; { eventualmente viene poi cambiato }
  2136.     for x:=1 to 4 do
  2137.         screen[px+x+row[py+5]]:=a;    { py+5 perche' il trattino in mezzo }
  2138.                                       { e' 5 pixel piu' sotto di quello   }
  2139.                                       { in altro.                         }
  2140.     { Bit 2 }
  2141.     a:=222;
  2142.     if (DIGITS[num] and 4)=4 then a:=223;
  2143.     for x:=1 to 4 do
  2144.         screen[px+x+row[py+10]]:=a;
  2145.  
  2146.     { Bit 3 }
  2147.     a:=222;
  2148.     if (DIGITS[num] and 8)=8 then a:=223;
  2149.     for y:=1 to 4 do
  2150.         screen[px+row[py+y]]:=a;
  2151.  
  2152.     { Bit 4 }
  2153.     a:=222;
  2154.     if (DIGITS[num] and 16)=16 then a:=223;
  2155.     for y:=1 to 4 do
  2156.         screen[px+row[py+y+5]]:=a;
  2157.  
  2158.     { Bit 5 }
  2159.     a:=222;
  2160.     if (DIGITS[num] and 32)=32 then a:=223;
  2161.     for y:=1 to 4 do
  2162.         screen[px+5+row[py+y]]:=a;
  2163.  
  2164.     { Bit 6 }
  2165.     a:=222;
  2166.     if (DIGITS[num] and 64)=64 then a:=223;
  2167.     for y:=1 to 4 do
  2168.         screen[px+5+row[py+y+5]]:=a;
  2169.  
  2170.     end;
  2171.  
  2172.  
  2173. { Stampa le 5 cifre del punteggio alle coordinate px,py }
  2174. procedure write_score(px,py : integer; sc : longint);
  2175. var n1 : longint;
  2176.     f  : boolean;
  2177.  
  2178.    begin
  2179.    f:=false; { Finche' questo rimane a false, gli 0 non vengono stampati  }
  2180.              { Questo per far si che' all'inizio il punteggio sia 0 e non }
  2181.              { 000000 che sta male.                                       }
  2182.  
  2183.    { prima cifra digitale }
  2184.    n1:=(sc div 100000) mod 10;
  2185.    if n1>0 then f:=true;          { Se la prima cifra e' >0 allora }
  2186.    if f then put_digit(px,py,n1)  { occorre stamparla }
  2187.    else put_digit(px,py,10);      { altrimenti stampa un numero spento }
  2188.  
  2189.    { seconda cifra digitale }
  2190.    n1:=(sc div 10000) mod 10;     { Idem per i restanti blocchi }
  2191.    if n1>0 then f:=true;
  2192.    if f then put_digit(px+7,py,n1)
  2193.    else put_digit(px+7,py,10);
  2194.  
  2195.    { terza cifra digitale }
  2196.    n1:=(sc div 1000) mod 10;
  2197.    if n1>0 then f:=true;
  2198.    if f then put_digit(px+14,py,n1)
  2199.    else put_digit(px+14,py,10);
  2200.  
  2201.    { quarta cifra digitale }
  2202.    n1:=(sc div 100) mod 10;
  2203.    if n1>0 then f:=true;
  2204.    if f then put_digit(px+21,py,n1)
  2205.    else put_digit(px+21,py,10);
  2206.  
  2207.    { quinta cifra digitale }
  2208.    n1:=(sc div 10) mod 10;
  2209.    put_digit(px+28,py,n1);
  2210.  
  2211.    { sesta e ultima cifra digitale (che ovviamente e' sempre 0 perche' }
  2212.    { il punteggio viaggia a multipli di 10 punti.                      }
  2213.    put_digit(px+35,py,0);
  2214.    end;
  2215.  
  2216. { Quando si richiama la pausa il controllo passa a questa procedura }
  2217. procedure pause_game;
  2218. var x,y,z : integer;
  2219.  
  2220.     begin
  2221.     nosound;                    { disattiva qualunque suono del cicalino }
  2222.     setcolor(0);                { Stampa la scritta in nero spostandola  }
  2223.     for x:=0 to 2 do            { in tutte le direzioni.                 }
  2224.         for y:=0 to 2 do
  2225.             outtextxy(66+x,129+y,'Game Paused');
  2226.  
  2227.     setcolor(1);                      { Indi stampa quella in bianco }
  2228.     outtextxy(67,130,'Game Paused');
  2229.  
  2230.     repeat
  2231.     z:=inkey;                        { e aspetta finche' non viene premuto }
  2232.     until (z=ord('p')) or (z=32);    { o la "p" o lo spazio (z=32)         }
  2233.  
  2234.  
  2235.     { Cancella la scritta ricopiandoci sopra il fondale }
  2236.     for y:=129 to 140 do
  2237.         memcpy(addr(playscreen.map^[66+row[y]]),
  2238.                addr(screen[66+row[y]]),textwidth('Game Paused')+1);
  2239.  
  2240.     { textwidth('Game Paused') e' una funziona che ritorna la lunghezza }
  2241.     { in pixel della scritta 'Game Paused'.                             }
  2242.     end;
  2243.  
  2244.  
  2245. { Stampa i vaus piccolini in basso a sinistra che indicano il numero di }
  2246. { vite che restano disponibili (senza contare quella in gioco).         }
  2247. procedure plot_lives(lives : integer);
  2248.  
  2249. const XLIVES = 11;
  2250.       YLIVES = 192;
  2251.  
  2252. var x,y,cn,
  2253.     xp,yp,
  2254.     xl,yl   : word;
  2255.     shadow  : integer;
  2256.  
  2257.     begin
  2258.     dec(lives); { Il numero di vite deve essere decrementato di uno }
  2259.                 { perche' non va contata quella in gioco.           }
  2260.  
  2261.     for cn:=0 to 7 do                       { al massimo ne disegna 8 }
  2262.         for y:=0 to minivaus.height-1 do
  2263.             for x:=0 to minivaus.width-1 do
  2264.                 begin
  2265.                 xl:=x+XLIVES+cn*minivaus.width;
  2266.                 yl:=y+YLIVES;
  2267.  
  2268.                 xp:=modx[xl];
  2269.                 yp:=mody[yl]*pattern.width;
  2270.  
  2271.                 { se il numero di vite e maggiore del contatore }
  2272.                 { allora disegna un vaus.                       }
  2273.                 if (lives>cn) and (minivaus.map^[x+y*minivaus.width]<>0) then
  2274.                    begin
  2275.                    screen[xl+row[yl]]:=minivaus.map^[x+y*minivaus.width];
  2276.                    playscreen.map^[xl+row[yl]]:=minivaus.map^[x+y*minivaus.width];
  2277.                    end
  2278.  
  2279.                 { altrimenti ricopia il fondale dello schermo in modo che }
  2280.                 { se il vaus era presente viene ora cancellato.           }
  2281.                 else
  2282.                   begin
  2283.                   shadow:=playscreen.map^[xl+row[yl]] and 128;
  2284.                   screen[xl+row[yl]]:=(pattern.map^[xp+yp] and 127) or shadow;
  2285.                   playscreen.map^[xl+row[yl]]:=(pattern.map^[xp+yp] and 127) or shadow;
  2286.                   end;
  2287.                 end;
  2288.     end;
  2289.  
  2290. procedure place_fire;
  2291. var y,fw : word;
  2292.     begin
  2293.     for y:=0 to shoots.height-1 do
  2294.         begin
  2295.         fw:=shoots.width*y;
  2296.         memzerocpy(addr(shoots.map^[fw]),
  2297.                    addr(screen[fire.x+row[y+fire.y]]),shoots.width);
  2298.         end;
  2299.     end;
  2300.  
  2301. procedure remove_fire;
  2302. var y,fw : word;
  2303.     begin
  2304.     for y:=0 to shoots.height-1 do
  2305.         begin
  2306.         fw:=shoots.width*y;
  2307.         memcpy(addr(playscreen.map^[fire.x+row[y+fire.y]]),
  2308.                addr(screen[fire.x+row[y+fire.y]]),shoots.width);
  2309.         end;
  2310.     end;
  2311.  
  2312. procedure check_fire;
  2313. var x1,x2,y1,y2 : word;
  2314.     begin
  2315.     if (fire.avl) then
  2316.        begin
  2317.        if (mouseclick=1) and (fire.avl) and (not fire.shot) then
  2318.           begin
  2319.           fire.x:=vaus.x+(vaus.width-shoots.width) shr 1;
  2320.           fire.y:=vaus.y-shoots.height;
  2321.           fire.shot:=TRUE;
  2322.           fire.nw  :=FALSE;
  2323.           ball_block_sound(700,5);
  2324.           end;
  2325.  
  2326.        if fire.shot then
  2327.           begin
  2328.           if fire.nw then remove_fire;
  2329.           fire.nw:=TRUE;
  2330.  
  2331.           dec(fire.y,4);
  2332.           if fire.y<22 then fire.shot:=FALSE
  2333.           else
  2334.               begin
  2335.               place_fire;
  2336.  
  2337.               if ((fire.y-22)>=0) and ((fire.y-22)<120) then
  2338.                  begin
  2339.                  x1:=(fire.x-9 ) shr 4;
  2340.                  y1:=(fire.y-22) shr 3;
  2341.  
  2342.                  x2:=(fire.x+shoots.width-9) shr 4;
  2343.                  y2:=y1;
  2344.  
  2345.                  if (wall[x1,y1]<>0) or (wall[x2,y2]<>0) then
  2346.                     begin
  2347.                     remove_fire;
  2348.                     fire.shot:=FALSE;
  2349.  
  2350.                     shoot_block_with_fire(x1,y1);
  2351.                     shoot_block_with_fire(x2,y2);
  2352.                     end;
  2353.                  end;
  2354.               end;
  2355.           end;
  2356.        end;
  2357.     end;
  2358.  
  2359. procedure remove_flux;
  2360. var y : word;
  2361.     begin
  2362.     for y:=0 to 19 do
  2363.         memcpy(addr(playscreen.map^[217+row[y+FLUXLEVEL]]),
  2364.                addr(screen[217+row[y+FLUXLEVEL]]),8);
  2365.     end;
  2366.  
  2367. procedure check_flux;
  2368. var y,fx  : word;
  2369.  
  2370.    begin
  2371.    fx:=scrfluxcnt;
  2372.    if scrflux then
  2373.       begin
  2374.       for y:=0 to 19 do
  2375.           memcpy(addr(flux.map^[(y+fx) shl 3]),
  2376.                  addr(screen[217+row[y+FLUXLEVEL]]),8);
  2377.  
  2378.       inc(scrfluxcnt);
  2379.       if scrfluxcnt>20 then scrfluxcnt:=0;
  2380.       end;
  2381.    end;
  2382.  
  2383. procedure vaus_out;
  2384. var x,y,z : word;
  2385.     begin
  2386.     nosound;
  2387.  
  2388.     inc(score.player[cur_player],10000);
  2389.     remain_blk:=0;
  2390.  
  2391.     z:=vaus.x;
  2392.  
  2393.     wait_vbl;
  2394.     remove_vaus;
  2395.     place_vaus;
  2396.  
  2397.     for x:=z to z+44 do
  2398.         begin
  2399.         Wait_VBL;
  2400.  
  2401.         vaus.oldx:=vaus.x;
  2402.         vaus.x:=x;
  2403.         remove_vaus;
  2404.         check_flux;
  2405.         place_vaus;
  2406.  
  2407.         for y:=vaus.y to vaus.y+vaus.height do
  2408.             memcpy(addr(playscreen.map^[225+row[y]]),
  2409.                    addr(screen[225+row[y]]),40);
  2410.  
  2411.  
  2412.         end;
  2413.  
  2414.     end;
  2415.  
  2416.  
  2417. procedure check_bonus_type(var b1,b2,b3 : BALLTYPE);
  2418. var x,y : longint;
  2419.     begin
  2420.       if vaus.letter>0 then
  2421.          begin
  2422.          lett.last:=vaus.letter-1;
  2423.          if b2.inplay then remove_ball(b2);
  2424.          if b3.inplay then remove_ball(b3);
  2425.          b2.inplay:=FALSE;
  2426.          b3.inplay:=FALSE;
  2427.          scrflux:=FALSE;
  2428.          remove_flux;
  2429.  
  2430.          if vaus.letter<>6 then
  2431.             begin
  2432.             b1.launch:=FALSE;
  2433.             b2.launch:=FALSE;
  2434.             b3.launch:=FALSE;
  2435.             end;
  2436.          end;
  2437.  
  2438.       case vaus.letter of
  2439.  
  2440.         1: begin                              { Lettera L }
  2441.            if fire.shot then remove_fire;
  2442.            playvaus:=lasers;
  2443.            modify_vaus;
  2444.            vaus.letter:=0;
  2445.            fire.avl:=TRUE;
  2446.            fire.shot:=FALSE;
  2447.            end;
  2448.  
  2449.         2: begin                              { Lettera E }
  2450.            if fire.shot then remove_fire;
  2451.            playvaus:=enlarged;
  2452.            modify_vaus;
  2453.            vaus.letter:=0;
  2454.            fire.avl:=FALSE;
  2455.            end;
  2456.  
  2457.         3: begin                              { Lettera B }
  2458.            if fire.shot then remove_fire;
  2459.            playvaus:=normal;
  2460.            modify_vaus;
  2461.            vaus.letter:=0;
  2462.            fire.avl:=FALSE;
  2463.            scrflux:=TRUE;
  2464.            end;
  2465.  
  2466.         4: begin                              { Lettera D }
  2467.            if fire.shot then remove_fire;
  2468.            playvaus:=normal;
  2469.            modify_vaus;
  2470.            fire.avl:=FALSE;
  2471.            end;
  2472.  
  2473.         5: begin                              { Lettera S }
  2474.            if fire.shot then remove_fire;
  2475.            playvaus:=normal;
  2476.            modify_vaus;
  2477.            vaus.letter:=0;
  2478.            x:=max(b1.speed-500,BALLSPEED);
  2479.            set_ball_speed(b1,x);
  2480.            fire.avl:=FALSE;
  2481.            end;
  2482.  
  2483.         6: begin                              { Lettera C }
  2484.            if fire.shot then remove_fire;
  2485.            playvaus:=normal;
  2486.            modify_vaus;
  2487.            fire.avl:=FALSE;
  2488.            end;
  2489.  
  2490.         7: begin                              { Lettera P }
  2491.            if fire.shot then remove_fire;
  2492.            playvaus:=normal;
  2493.            modify_vaus;
  2494.            vaus.letter:=0;
  2495.            inc(score.lives[cur_player]);
  2496.            plot_lives(score.lives[cur_player]);
  2497.            ball_block_sound(2000,10);
  2498.            fire.avl:=FALSE;
  2499.            end;
  2500.  
  2501.         end;
  2502.      end;
  2503.  
  2504. procedure deviate_ball(var ball : BALLTYPE);
  2505. var temp : integer;
  2506.  
  2507.    begin
  2508.    repeat
  2509.    temp:=get_ball_direction(ball)+random(BALLDEV)-(BALLDEV shr 1);
  2510.    until ((temp mod 90)>30) and ((temp mod 90)<60);
  2511.  
  2512.    set_ball_direction(ball,temp);
  2513.    set_ball_speed(ball,ball.speed);
  2514.    ball.sbd:=0;
  2515.    end;
  2516.  
  2517. { ------------------------------------------------------------------------ }
  2518.  
  2519. { Questa e' la procedura principale che durante il gioco chiama tutte le  }
  2520. { altre. Finche' la palla non viene persa o il quadro viene terminato     }
  2521. { (o eventualmente viene abortita la partita) la procedura mantiene il    }
  2522. { controllo. Termina in uno solo in uno dei casi sopra citati o in caso   }
  2523. { si verifichi un fatal_error a causa del quale il programma e' costretto }
  2524. { a quittare automaticamente e inevitabilmente.                           }
  2525.  
  2526.  
  2527. function Bounceball : boolean;
  2528. var
  2529.   x,y  : integer;
  2530.   key  : integer;
  2531.   ball : array[1..3] of BALLTYPE;
  2532.   stm  : integer;
  2533.   temp : integer;
  2534.   t1,t2: longint;
  2535.  
  2536.   begin
  2537.   scrfluxcnt:=0;
  2538.   scrflux:=FALSE;
  2539.  
  2540.   balls_in_play:=1;
  2541.  
  2542.   fire.avl:=FALSE;
  2543.   playvaus:=normal;
  2544.  
  2545.   lett.last:=EMP;
  2546.   lett.active:=FALSE;
  2547.  
  2548.   { Mette lo sfondo giusto a seconda del muro }
  2549.   fill_picture_with_pattern(pattern);
  2550.  
  2551.   { Disegna il quadro di gioco con lo sfondo pocanzi settato}
  2552.   showBTMpicture(playscreen);
  2553.  
  2554.   { Stampa il numero delle vite del giocatore corrente }
  2555.   { cur_player=1 o 2 a seconda di quale giocatore deve giocare }
  2556.   plot_lives(score.lives[cur_player]);
  2557.  
  2558.   { regola i colori, in teoria dovrebbero gia' essere a posto. }
  2559.   setpalette(playscreen);
  2560.  
  2561.   { Stampa il punteggio dei 2 giocatori e l'hi-score. }
  2562.   write_score(253,POS_DIGIT[1],score.player[1]);
  2563.   write_score(253,POS_DIGIT[2],score.player[2]);
  2564.   write_score(253,POS_DIGIT[3],score.hiscore);
  2565.  
  2566.   { Disegna i mattoncini }
  2567.   put_wall;
  2568.  
  2569.   { Esegue un reset nel caso il mouse abbia qualche problema, alle volte }
  2570.   { succede. }
  2571.   mousereset;
  2572.  
  2573.   { La palla e' in gioco e deve essere lanciata }
  2574.   ball[1].inplay:=TRUE;
  2575.   ball[1].launch:=TRUE;
  2576.  
  2577.   { Setta le coordinate iniziali della palla }
  2578.   ball[1].x:=((SCRMAX+SCRMIN) shr 1)-2;
  2579.   ball[1].y:=VAUS_LINE-BALLSPOT;
  2580.  
  2581.   { annulla quelle vecchie }
  2582.   ball[1].oldx:=EMP;
  2583.   ball[1].oldy:=EMP;
  2584.  
  2585.   { La deviazione avviene quando questo valore supera una certa soglia }
  2586.   ball[1].sbd:=0;
  2587.  
  2588.   { La distanza iniziale della palla quando si trova sul vaus dal bordo }
  2589.   { sinistro del vaus stesso.                                           }
  2590.   ball[1].onvaus:=16;
  2591.  
  2592.   { Tiene il numero di vertical-blank che passano da quando appare   }
  2593.   { il vaus con la pallina a quando essa viene lanciata.              }
  2594.   { Se il valore supera le 2000 unita' la palla parte automaticamente }
  2595.   ball[1].stm:=0;
  2596.  
  2597.   { Alla partenza la variabile lett.incoming assume un valore casuale }
  2598.   { fra 0 e LETTER_DROP (costante definita all'inizio della unit.     }
  2599.   lett.incoming:=random(LETTER_DROP);
  2600.  
  2601.   { Mostra l'animazione del vaus che si materializza dal nulla }
  2602.   create_vaus;
  2603.  
  2604.   { e stampa la scritta ROUND xx, READY. }
  2605.   write_round_level;
  2606.  
  2607.   set_vaus;                       { Regola i parametri iniziali del vaus. }
  2608.   start_vaus;
  2609.   move_vaus(vaus.x,VAUS_LINE);    { lo porta al centro dell'area di gioco }
  2610.   start_level;                    { Se il suono e' attivo fa la musichetta }
  2611.   start_vaus;
  2612.   remove_round_level;             { Toglie la scritta ROUND xx, READY }
  2613.   set_ball(ball[1]);
  2614.  
  2615.   { Questo e' il ciclo principale, puo' uscire da esso solo se : }
  2616.   { - la palla viene persa,                                      }
  2617.   { - il quadro viene terminato (cioe' non restano piu' mattoni  }
  2618.   {   da distruggere.                                            }
  2619.   { - la partita viene in qualche modo abortita.                 }
  2620.  
  2621.   set_ball_direction(ball[1],random(15)+60); { angolo di partenza casuale }
  2622.                                              { 60 e 75 gradi }
  2623.   set_ball_speed(ball[1],BALLSPEED);
  2624.  
  2625.   { velocita' iniziale = BALLSPEED costante }
  2626.   ball[1].finespeed:=0; { i sottomultipli della velocita' sono 0  }
  2627.  
  2628.   ball[2].inplay:=FALSE;
  2629.   ball[3].inplay:=FALSE;
  2630.  
  2631.   while(ball[1].inplay) and (remain_blk>0) and (not score.abortplay) do
  2632.      begin
  2633.      Wait_VBL; { Attende il vertical blank }
  2634.  
  2635.      mousecoords(x,y);  { legge le coordinate del mouse }
  2636.  
  2637.      { se il trainer (vaus in modalita' automatica) non e' attiva }
  2638.      { muove il vaus alla coord.x del mouse.                      }
  2639.      if trainer=0 then move_vaus(x,VAUS_LINE)
  2640.  
  2641.      { se invece e' attivo impone che la x del vaus sia uguale alla x della }
  2642.      { palla, con un opportuno coefficiente di traslazione per far si che   }
  2643.      { la palla batta al centro del vaus e non sul bordo sinistro.          }
  2644.      else if trainer=1 then
  2645.           move_vaus(min(SCRMAX-32,max(ball[1].x-ball[1].onvaus,SCRMIN)),VAUS_LINE);
  2646.  
  2647.      { ball[1].launch vale TRUE se la palla e' attaccata al vaus e deve }
  2648.      { essere lanciata. Altrimenti quando e' in gioco vale false.       }
  2649.      if ball[1].launch=TRUE then
  2650.         begin
  2651.         inc(ball[1].stm);  { se la palla e' attaccata il contatore di scatti }
  2652.                            { viene continuamente incrementato.               }
  2653.  
  2654.  
  2655.         { Quando raggiunge quota 250 la palla parte automaticamente }
  2656.         if ball[1].stm=250 then ball[1].launch:=FALSE;
  2657.  
  2658.         { Fa in modo che la palla segua il vaus se questo viene spostato }
  2659.         start_ball(ball[1]);
  2660.  
  2661.         { Se si preme il tasto del mouse allora la palla parte }
  2662.         if mouseclick=1 then ball[1].launch:=FALSE;
  2663.         end
  2664.  
  2665.      else
  2666.         { altrimenti se la palla non e' attaccata occorre semplicemente   }
  2667.         { muoverla. Chiaramente se le palle sono 3 bisogna muoverle tutte }
  2668.         { e tre.                                                          }
  2669.         for cn:=1 to 3 do
  2670.             if ball[cn].inplay then move_ball(ball[cn]);
  2671.  
  2672.      { Se le coord. della pallina cn sono comprese fra 22 e 142 (rispettivamente }
  2673.      { massima e minima coord. in cui si puo' urtare un mattoncino) allora }
  2674.      { occorre controllare se la palla ha effettivamente urtato un mattoncino }
  2675.      { oppure no. }
  2676.  
  2677.      for cn:=1 to 3 do
  2678.          begin
  2679.          if (ball[cn].inplay) then   { tutte le considerazioni valgono se }
  2680.                                      { la palla e' in gioco.              }
  2681.             begin
  2682.             if (ball[cn].y>=22) and (ball[cn].y<142) then
  2683.                ball_hit_block(ball[cn]);
  2684.  
  2685.             set_ball(ball[cn]);
  2686.             ball[cn].speed:=ball_speed(ball[cn]);
  2687.             end;
  2688.          end;
  2689.  
  2690.      checkshine;     { controlla se c'e' da far scintillare un mattoncino }
  2691.      check_letter;   { se sta scendendo una lettera }
  2692.      check_bonus_type(ball[1],ball[2],ball[3]); { se viene raccolta una lettera }
  2693.      check_fire;     { se e' stato sparato un colpo di laser }
  2694.      check_flux;
  2695.  
  2696.      if ((vaus.x+vaus.width)=(SCRMAX-1)) and (scrflux) then vaus_out;
  2697.  
  2698.      if vaus.letter=4 then   { nel caso sia stata raccolta una D le palle }
  2699.         begin                { diventano 3.                               }
  2700.         balls_in_play:=3;
  2701.  
  2702.         ball[2]:=ball[1];    { la palla 2 e 3 vengono poste uguale alla 1 }
  2703.         ball[3]:=ball[1];
  2704.  
  2705.         t1:=get_ball_direction(ball[1]) div 90;
  2706.         { si il quadrante in cui si trova il vettore velocita' }
  2707.         t2:=ball[1].speed;  { nonche' il modulo del vettore stesso }
  2708.  
  2709.         { si impone un inclinazione di 30 gradi rispetto al quadrante alla }
  2710.         { prima palla, di 45 alla seconda e di 60 alla terza.              }
  2711.  
  2712.         { A questo punto le tre palle sono costrette a dividersi. }
  2713.  
  2714.         set_ball_direction(ball[1],(t1*90+30));
  2715.         set_ball_direction(ball[2],(t1*90+45));
  2716.         set_ball_direction(ball[3],(t1*90+60));
  2717.  
  2718.  
  2719.         { Le tre velocita' invece rimangono quella della prima palla }
  2720.         set_ball_speed(ball[1],t2);
  2721.         set_ball_speed(ball[2],t2);
  2722.         set_ball_speed(ball[3],t2);
  2723.  
  2724.         vaus.letter:=0;
  2725.         end;
  2726.  
  2727.      { finche' c'e' piu' di una palla in gioco, nessuna lettera deve arrivare }
  2728.      if balls_in_play>1 then lett.incoming:=0;
  2729.  
  2730.      { Aggiorna lo score del giocatore }
  2731.      write_score(253,POS_DIGIT[cur_player],score.player[cur_player]);
  2732.  
  2733.      { Se lo score del giocatore e maggiore dell'hi-score }
  2734.      if score.player[cur_player]>score.hiscore then
  2735.         begin
  2736.         { pone l'hi-score uguale allo score del giocatore }
  2737.         score.hiscore:=score.player[cur_player];
  2738.         { e stampa l'hi-score sullo schermo }
  2739.         write_score(253,POS_DIGIT[3],score.hiscore);
  2740.         end;
  2741.  
  2742.      { Questo ciclo aumenta la velocita' di tutte le palle in gioco        }
  2743.      { il valore di LEVEL[lv] dipende ovviamente dal lv, cioe' dal livello }
  2744.      { selezionato prima di cominciare la partita.                         }
  2745.  
  2746.      for cn:=1 to 3 do
  2747.          begin
  2748.          if ball[cn].inplay then
  2749.             begin
  2750.             inc(ball[cn].finespeed);
  2751.             if ball[cn].finespeed>LEVEL[lv] then
  2752.                begin
  2753.                ball[cn].finespeed:=0;
  2754.  
  2755.                { se la velocita' e' inferiore a quella massima }
  2756.                if ball[cn].speed<MAXSPEED then
  2757.                   begin
  2758.                   inc(ball[cn].speed,10);  { la si incrementa }
  2759.                   set_ball_speed(ball[cn],ball[cn].speed); { e la si aggiorna }
  2760.                   end;
  2761.                end;
  2762.  
  2763.             inc(ball[cn].sbd); { questo e' il contatore di deviazione regolare }
  2764.  
  2765.             { se supera una certa soglia (SBDIR) viene imposta una deviazione }
  2766.             { casuale di un angolo compreso fra i -BALLDEV/2 e +BALLDEV/2 }
  2767.             if (ball[cn].sbd>=SBDIR) and (ball[cn].speedy<0) then
  2768.                deviate_ball(ball[cn]);
  2769.             end;
  2770.          end;
  2771.  
  2772.      { Questo ciclo fa in modo che la palla n.1 sia sempre in gioco }
  2773.      { (a meno che non vengano perse tutte e tre) }
  2774.  
  2775.      { Se si pedre la n.1, la n.2 prende il posto della n.1, la n.3 prende }
  2776.      { il posto nella n.2, infine la n.3 viene disattivata                 }
  2777.  
  2778.      { poiche' le tre palle sono uguali, il processo avviene senza che il  }
  2779.      { giocatore percepisca materialmente la sostituzione.                 }
  2780.  
  2781.      { in questo modo se terminato il ciclo la palla n.1 risulta non essere }
  2782.      { in gioco, significa che tutte e tre sono cadute. }
  2783.  
  2784.      for cn:=1 to 3 do
  2785.          if not ball[1].inplay then
  2786.             begin
  2787.             ball[1]:=ball[2];
  2788.             ball[2]:=ball[3];
  2789.             ball[3].inplay:=FALSE;
  2790.             end;
  2791.  
  2792.      balls_in_play:=0;  { Si ricalcola ogni volta il numero delle palle in }
  2793.      for cn:=1 to 3 do  { gioco. }
  2794.          if ball[cn].inplay then inc(balls_in_play);
  2795.  
  2796.  
  2797.      if (not ball[1].inplay) then   { Se la palla n.1 non e' piu' in gioco }
  2798.         begin
  2799.         ball[1].launch:=TRUE;
  2800.         remove_ball(ball[1]);         { la si toglie dallo schermo }
  2801.         destroy_vaus;                 { mostra la sequenza di distruzione }
  2802.         dec(score.lives[cur_player]); { decrementa di 1 il numero delle vite }
  2803.         score.wall_p[cur_player]:=wall; { memorizza il una variabile assegnata }
  2804.                                         { al giocatore il muro corrente }
  2805.         { Questo accade perche' se i giocatori sono due, occorre passare }
  2806.         { all'altro giocatore che probabilmente non si trovera nella stessa }
  2807.         { posizione. I mattoncini devono poi essere riportati tali e quali }
  2808.         { quando il turno passa di nuovo al giocatore che ora a perso una  }
  2809.         { vita. }
  2810.  
  2811.         nosound; { e disabilita' il suono }
  2812.         end;
  2813.  
  2814.  
  2815.      { Se la nota corrente dura finche' snd_delay non diventa 0 }
  2816.      if snd_delay>0 then dec(snd_delay)
  2817.      else nosound;
  2818.  
  2819.      { ---------------------- Trainer Options -------------------- }
  2820.  
  2821.      key:=inkey;  { si guarda se viene premuto un tasto }
  2822.  
  2823.      if (key=ord('p')) or (key=32) then pause_game; { Il tasto P pausa il gioco }
  2824.  
  2825.      if key=7680 then score.abortplay:=TRUE;  { ALT+A, la partita e' abortita }
  2826.  
  2827.      if (key=ord('T')) then { Se si preme la T (maiuscola) viene generata }
  2828.         begin               { una fila di mattoncini. }
  2829.         for cn:=0 to 12 do
  2830.             begin
  2831.             { Chiaramente se il mattoncino indistruttibile deve sostituire }
  2832.             { un altro mattoncino distruttibile, bisogna che il numero totale }
  2833.             { di mattoncini da abbattere per finire il quadro diminuisca di 1 }
  2834.             if (wall[cn,14]>0) and (wall[cn,14]<>10) then
  2835.                dec(remain_blk);
  2836.  
  2837.             wall[cn,14]:=10;  { e il mattoncino in questione diventa indistruttibile }
  2838.             end;
  2839.  
  2840.         put_wall; { e viene fatto l'aggiornamento sullo schermo }
  2841.         end;
  2842.  
  2843.      { La 'R' maiuscola abilita la modalita' automatica del vaus }
  2844.      if key=ord('R') then trainer:=1;
  2845.  
  2846.      { La 'r' minuscola la disabilita }
  2847.      if key=ord('r') then trainer:=0;
  2848.  
  2849.      { Se il tasto e' una a,b,c,d,e,f,g: viene fatta cadere una lettera }
  2850.      if (key>=97) and (key<(97+LETTER_NUMB-1)) then { Fa cadere la lettera }
  2851.         start_letter(104,30,key-97);
  2852.  
  2853.      if key=11520 then                        { ALT+X, quit-ta }
  2854.         begin
  2855.         closegraph;
  2856.         nosound;
  2857.         closeprogram;
  2858.         end;
  2859.  
  2860.      end;
  2861.  
  2862.   { BounceBall esce con false se la palla e' stata persa, con true se }
  2863.   { il quadro e' stato finito. }
  2864.  
  2865.   Bounceball:=FALSE;
  2866.   if remain_blk=0 then Bounceball:=TRUE;
  2867.   end;
  2868.  
  2869. { ------------------------------------------------------------- }
  2870.  
  2871. function choose_start_wall : integer;
  2872. const px = 70;
  2873.       py = 100;
  2874.       dx = 34;
  2875.       dy = 35;
  2876.       ddx= 19;
  2877.       ddy= 14;
  2878.  
  2879. var x,y,z : longint;
  2880.     st    : integer;
  2881.     oldx,
  2882.     oldy,
  2883.     newx,
  2884.     newy  : integer;
  2885.     sc    : string[20];
  2886.  
  2887.     begin
  2888.     st:=1;  { Si comincia a scegliere partendo dal muro n.1 }
  2889.  
  2890.     settextstyle(DefaultFont,HorizDir,1);
  2891.     setcolor(0);
  2892.  
  2893.     { Stampa PLAYER xxx se il numero di giocatori e' 2 }
  2894.     if cur_player=1 then sc:='Player One'
  2895.     else sc:='Player Two';
  2896.  
  2897.     { stampa le scritte CHOOSE YOER WALL, ecc... }
  2898.     for x:=-1 to 1 do
  2899.         for y:=-1 to 1 do
  2900.             begin
  2901.             outtextxy(px+5+x,py+y,sc);
  2902.             outtextxy(px+x,py+y+10,'Choose your');
  2903.             outtextxy(px+6+x,py+y+20,'start wall');
  2904.  
  2905.             outtextxy(px-39+x,py+58+y,'Move mouse to select;');
  2906.             outtextxy(px-45+x,py+68+y,'left button to confirm');
  2907.             end;
  2908.  
  2909.     setcolor(1);
  2910.     outtextxy(px+5,py,sc);
  2911.     outtextxy(px,py+10,'Choose your');
  2912.     outtextxy(px+6,py+20,'start wall');
  2913.  
  2914.     outtextxy(px-39,py+58,'Move mouse to select;');
  2915.     outtextxy(px-45,py+68,'left button to confirm');
  2916.  
  2917.     { Disegna il quadrato nero in cui devono apparire i numeri del muro }
  2918.     { da scegliere.                                                     }
  2919.     for y:=py+dy to py+dy+ddy do
  2920.         for x:=px+dx to px+dx+ddx do
  2921.             screen[x+row[y]]:=0;
  2922.  
  2923.     mousecoords(oldx,oldy);  { rileva le coordinate del mouse }
  2924.  
  2925.     while(mouseclick=1) do;
  2926.     while(mouseclick<>1) do
  2927.        begin
  2928.        put_digit(px+dx+3,py+dy+2,st div 10); { Scrive il numero del quadro }
  2929.        put_digit(px+dx+11,py+dy+2,st mod 10);
  2930.  
  2931.        mousecoords(newx,newy);       { Se le coord. sono diverse: }
  2932.        if newx>oldx then inc(st);    { se la x e' maggiore il quadro aumenta }
  2933.        if newx<oldx then dec(st);    { se e' munore diminuisce.              }
  2934.  
  2935.        { Se supera il massimo selezionabile torna al n.1 }
  2936.        if st>totalwall then st:=st-totalwall;
  2937.  
  2938.        { se supera il minimo selezionabile torna al massimo (n.32) }
  2939.        if st<1 then st:=st+totalwall;
  2940.  
  2941.        oldx:=newx; { le nuove coord. diventano le vecchie. }
  2942.        oldy:=newy;
  2943.  
  2944.        end;
  2945.  
  2946.     choose_start_wall:=st;  { e ritorna il numero selezionato }
  2947.     end;
  2948.  
  2949. procedure set_start_parameters;
  2950. var x : integer;
  2951.    begin
  2952.    { Imposta i parametri del giocatore 1 e 2 }
  2953.  
  2954.    for x:=1 to 2 do
  2955.        begin
  2956.        score.player[x]:=0;
  2957.        score.lives[x] :=5;
  2958.        score.wall_n[x]:=STARTWALL;
  2959.        score.wall_p[x]:=all_walls[STARTWALL-1];
  2960.        score.roundsel[x]:=FALSE;
  2961.        end;
  2962.  
  2963.    cur_player:=1;
  2964.    end;
  2965.  
  2966. procedure soundicon;
  2967. var x,y,fl,fw,h : word;
  2968.  
  2969.     begin
  2970.     { Altezza dell'icona (l'icona e' alta il doppio perche' il brush }
  2971.     { e' composto dall'icona con la nota e l'icona con la X una sopra l'altra }
  2972.     h:=soundfx.height div 2;
  2973.  
  2974.     fl:=0; { se sound_on non e' false, cioe' e' TRUE allora fl:=0 }
  2975.            { punto in cui inizia il disegno dell'icona con la nota }
  2976.  
  2977.  
  2978.     { altrimenti fl viene spostato al punto in cui c'e' l'icona con la X }
  2979.     if sound_on=FALSE then
  2980.        fl:=soundfx.width*h;
  2981.  
  2982.     { e quindi copia uno dei due disegni sullo schermo }
  2983.     for y:=0 to h-1 do
  2984.         begin
  2985.         fw:=y*soundfx.width;
  2986.         for x:=0 to soundfx.width-1 do
  2987.             screen[320-soundfx.width+x+row[y+200-h]]:=soundfx.map^[x+fw+fl];
  2988.         end;
  2989.     end;
  2990.  
  2991. procedure level_selection;
  2992. var x,y,fl,fw,h : word;
  2993.  
  2994.     begin
  2995.     { Disegna sullo schermo uno dei 5 numeri a seconda del valore di lv }
  2996.     h:=levelsel.height div 5;    { I frames sono 5 quindi l'altezza di un }
  2997.                                  { frame e' l'altezza totale del disegno/5 }
  2998.  
  2999.     fl:=(lv-1)*h*levelsel.width; { fl contiene l'indirizzo del frame da }
  3000.                                  { copiare sullo schermo.               }
  3001.  
  3002.     for y:=0 to h-1 do
  3003.         begin
  3004.         fw:=y*levelsel.width;
  3005.         for x:=0 to levelsel.width-1 do
  3006.             screen[x+row[y+200-h]]:=levelsel.map^[x+fw+fl];
  3007.         end;
  3008.     end;
  3009.  
  3010. function mainscreen : integer;
  3011. var x,y,z : word;
  3012.     ps    : integer;
  3013.     srow  : array[0..100] of word;
  3014.     k,ik  : integer;
  3015.  
  3016.     begin
  3017.     nosound;                { spegne il cicalino }
  3018.     score.abortplay:=FALSE; { e' imposta il flag di partita abortita a FALSE }
  3019.  
  3020.     for x:=0 to 63999 do    { Cancella lo schermo }
  3021.         screen[x]:=0;
  3022.  
  3023.     setpalette(playscreen); { Imposta i colori }
  3024.  
  3025.     { E copia la pagina di presentazione con la scritta ARKANOID sullo schermo }
  3026.     { tramite la procedura scritta in assembler. }
  3027.     memcpy(addr(presents.map^),addr(screen),64000);
  3028.  
  3029.     soundicon;         { disegna l'icona del suono }
  3030.     level_selection;   { e quella del livello }
  3031.     mousereset;        { resetta il mouse per precauzione }
  3032.  
  3033.     repeat             { cicla finche' non viene fatto qualcosa }
  3034.        { k tiene lo stato del mouse, ik gli eventuali tasti premuti }
  3035.  
  3036.        k:=mouseclick;
  3037.        ik:=inkey;
  3038.  
  3039.        if ik=11520 then k:=-1;   { ALT+X = quit }  { k<>0 interrompe il ciclo }
  3040.  
  3041.  
  3042.        if ik=32 then             { SPACE BAR = switch del suono on/off }
  3043.           begin
  3044.           sound_on:=sound_on XOR TRUE;    { x xor 1 inverte il valore di x }
  3045.           soundicon; { e disegna l'icona} { 0 xor 1 = 1; 1 xor 1 = 0 }
  3046.           end;
  3047.  
  3048.        if ik=15104 then    { se si preme F1 il livello aumenta }
  3049.           begin
  3050.           inc(lv);
  3051.           if lv>5 then lv:=1;   { se e' superiore a 5 torna ad 1 }
  3052.           level_selection;      { e stampa il numero sullo schermo }
  3053.           end;
  3054.  
  3055.        if ik=15360 then    { se si preme F2 il livello diminuisce }
  3056.           begin
  3057.           dec(lv);
  3058.           if lv<1 then lv:=5;  { se e' inferiore a 1 torna a 5 }
  3059.           level_selection;     { e stampa il numero sullo schermo }
  3060.           end;
  3061.  
  3062.     until k<>0;    { il ciclo si interrompe se k e' diverso da 0 }
  3063.  
  3064.     mainscreen:=k; { ritorna dunque: -1=quit, 1=un giocatore, 2=due giocatori }
  3065.     end;
  3066.  
  3067. procedure start_game(players : integer);
  3068. var nwall : boolean;
  3069.  
  3070.     begin
  3071.     set_start_parameters;                 { imposta i parametri di partenza }
  3072.     if players=1 then score.lives[2]:=0;  { se c'e' un solo giocatore il }
  3073.                                           { seconda non ha neanche una vita }
  3074.  
  3075.     trainer:=0;                           { il trainer viene disattivato }
  3076.     wall:=score.wall_p[cur_player];       { si copia nel muro corrente }
  3077.                                           { quello del giocatore corrente }
  3078.     set_wall;                             { e lo si disegna }
  3079.  
  3080.     fill_picture_with_pattern(pattern);   { si imposta lo sfondo }
  3081.     showBTMpicture(playscreen);           { e si disegna tutto quanto sullo }
  3082.                                           { schermo }
  3083.  
  3084.     setpalette(playscreen);               { si impostano i colori. }
  3085.  
  3086.     { si stampano i tre punteggi, player 1, 2 e hi-score }
  3087.     write_score(253,POS_DIGIT[1],score.player[1]);
  3088.     write_score(253,POS_DIGIT[2],score.player[2]);
  3089.     write_score(253,POS_DIGIT[3],score.hiscore);
  3090.  
  3091.     { e si disegnano i mattoncini del muro }
  3092.     put_wall;
  3093.  
  3094.     repeat
  3095.  
  3096.           repeat
  3097.              { se non e' ancora stato scelto il muro da cui partire }
  3098.              { viene fatto scegliere al giocatore (cur_player) ora  }
  3099.              if not score.roundsel[cur_player] then
  3100.                 begin
  3101.                 score.wall_n[cur_player]:=choose_start_wall;
  3102.  
  3103.                 { viene assegnato il muro scelto al giocatore }
  3104.                 score.wall_p[cur_player]:=
  3105.                       all_walls[score.wall_n[cur_player]-1];
  3106.  
  3107.                 { a questo punto e' stato scelto il muro }
  3108.                 score.roundsel[cur_player]:=TRUE;
  3109.                 end;
  3110.  
  3111.              { viene messo il muro del giocatore nel muro corrente }
  3112.              wall:=score.wall_p[cur_player];
  3113.              set_wall;
  3114.  
  3115.              { Si parte, questa assegnazione chiama bounceball, che non }
  3116.              { termina finche ho vieen perso il vaus o viene terminato  }
  3117.              { il quadro.                                               }
  3118.              nwall:=BounceBall;
  3119.  
  3120.  
  3121.              { Se viene terminato il quadro nwall vale TRUE }
  3122.              if nwall then
  3123.                 begin
  3124.                 { quindi si incrementa il numero del muro a cui si trova }
  3125.                 { il giocatore cur_player }
  3126.                 inc(score.wall_n[cur_player]);
  3127.  
  3128.                 { e se viene superato il numero massimo si riparte dal n.1 }
  3129.                 if score.wall_n[cur_player]>totalwall then
  3130.                    score.wall_n[cur_player]:=1;
  3131.  
  3132.                 { e viene prelevato in nuovo muro dalla matrice generale }
  3133.                 score.wall_p[cur_player]:=
  3134.                       all_walls[score.wall_n[cur_player]-1];
  3135.                 end
  3136.              else
  3137.                  { se non e' stato completato il muro si guarda se il numero }
  3138.                  { delle vite e' sceso a zero }
  3139.                  { nel qual caso si stampa la scritta GAME OVER }
  3140.                  if score.lives[cur_player]=0 then Game_Over;
  3141.  
  3142.           { il ciclo si ripete finche bounceball dice che non e' stato }
  3143.           { completato il muro (nwall=FALSE) il che significa che e' stata }
  3144.           { persa una vita }
  3145.           until nwall=FALSE;
  3146.  
  3147.           { allora il controllo passa all'altro giocatore }
  3148.           inc(cur_player);
  3149.           if cur_player>players then cur_player:=1;
  3150.  
  3151.           { a meno che un giocatore non abbia terminato il numero di vite    }
  3152.           { a disposizione, nel qual caso il controllo resta del giocatore   }
  3153.           { che ha perso la vita. Notare che questo funziona benissimo anche }
  3154.           { se c'e' un giocatore solo, poiche' l'altro giocatore ha le vite  }
  3155.           { a 0.                                                             }
  3156.           if score.lives[cur_player]=0 then cur_player:=3-cur_player;
  3157.  
  3158.  
  3159.     { il ciclo si ripete finche entrambi i giocatori non esauriscono le vite }
  3160.     { o la partita viene abortita con ALT+A }
  3161.     until ((score.lives[1]=0) and (score.lives[2]=0)) or (score.abortplay);
  3162.     end;
  3163.  
  3164. end.
  3165.  
  3166.  
  3167.  
  3168.  
  3169.  
  3170.  
  3171.  
  3172.  
  3173.  
  3174.  
  3175.  
  3176.