home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol080 / artil-z.pas < prev    next >
Pascal/Delphi Source File  |  1985-02-09  |  11KB  |  367 lines

  1. PROGRAM Artillery_Battle ;  { Pascal/Z Version }
  2.  
  3. {$C-, F-, M-, L-  (Turn off checking and listing options for better speed) }
  4.  
  5.   { *** WRITTEN BY    Jim Bearden
  6.             Cancer Center, University of Hawaii
  7.             1236 Lauhala Street
  8.             Honolulu, Hawaii 96813
  9.  
  10.     *** DATE WRITTEN    December, 1981
  11.  
  12.     *** PROGRAM SUMMARY:
  13.       This program simulates an artillery battle between two players.
  14.     The initial setup (ground elevation on each side, locations of
  15.     bunkers, height of the central "hill" or "valley", and wind
  16.     direction and velocity) is generated by the pseudo-random-number
  17.     procedure, depending on the "seed" number entered at the beginning.
  18.     Each player then enters the angle (in degrees above the horizontal)
  19.     and velocity (in meters per second) of his shot (NOTE that because
  20.     of the console I/O requirements of Pascal/Z, these two numbers MUST
  21.     be separated by a space, not a comma, and followed by <Return>).
  22.     Flight and impact point are displayed for the projectile, as long as it
  23.     remains on the screen. This program uses only ASCII characters and
  24.     cursor positioning (no graphics capability required), so it should
  25.     be usable on any CRT terminal with an addressable cursor (presently
  26.     set up for a 24 x 80 screen size, but may be adapted to other sizes
  27.     by changing constants as shown). You might also try changing the
  28.     scale factor, maximum wind velocity, or wind "coupling factor"
  29.     (its effect on the projectile) to get some other interesting
  30.     variations on the game.
  31.       Note that this version was named "ARTIL/Z" to distinguish it from
  32.     the other version (ARTIL/M) in Pascal/M. Unfortunately, the Pascal/Z
  33.     compiler, assembler, and/or linker will not accept a large number of
  34.     perfectly legal CP/M file names, including that one. Rename it to 
  35.     plain "ARTIL" before trying to compile it.
  36.   }
  37.  
  38.  
  39.  
  40.  
  41.   CONST
  42.     Grnd_sym  = '-' ; { Character used to represent ground surface in profile }
  43.     Burst_sym = '*' ; { Represents point of impact on ground }
  44.     Air_sym   = '+' ; { Represents projectile in flight }
  45.     Max_X     =  79 ; { Number of screen columns - 1 }
  46.     Max_Y     =  20 ; { Number of screen lines - 4 }
  47.     Scale     = 100 ; { Number of meters represented by each screen unit } 
  48.     Max_wind  =  25 ; { Maximum allowed wind velocity, in meters/sec }
  49.     Side_1    =  25 ; { Width of level ground section on player 1's side }
  50.     Side_2    =  25 ; { Same, player 2's side }
  51.     Center    =  30 ; { Width of center ("hill" or "valley") section }
  52.       { Sum of (Side_1 + Side_2 + Center) must equal width of screen }
  53.     Acc_g     = 9.8 ; { Acceleration of normal earth gravity, in meters/sec }
  54.     Bell      =   7 ; { ASCII code for "bell" sound }
  55.  
  56.   VAR
  57.     X_pos_1, X_pos_2,    { Locations (on X-axis) of bunkers of players 1 and 2 }
  58.     Level_1, Level_2,    { Heights of level ground sections on each side }
  59.     Center_ht        : 0..Max_X ;
  60.     Wind_vel        : -Max_wind..Max_wind ;
  61.     Ground        : ARRAY [0..Max_X] OF Integer ;
  62.     Direct_hit        : ARRAY [1..2] OF Boolean ;
  63.     Rand_num        : Integer ;
  64.     Answer        : Char ;
  65.     Quit        : Boolean ;
  66.  
  67.  
  68. {$IGOTOXY.PSP }   { PROCEDURE GotoXY (X_pos, Y_pos : Integer) }
  69.  
  70.  
  71. {$ICONACT.PSP }   { PROCEDURE Conact (Action : Integer) }
  72.  
  73.  
  74. {$IRANDOM.PSP }   { FUNCTION Random (VAR Seed : Integer) : Real }
  75.  
  76.  
  77. PROCEDURE Set_Up_Game ;
  78.  
  79.   VAR
  80.     X, Y  : 0..Max_X ;
  81.  
  82. BEGIN { Set_Up_Game }
  83.  
  84.   { Set up initial conditions from random-number generator }
  85.   Level_1 := Round (Max_Y * Random (Rand_num) / 2) ;
  86.   Level_2 := Round (Max_Y * Random (Rand_num) / 2) ;
  87.   Center_ht := Round (Max_Y * Random (Rand_num)) ;
  88.   X_pos_1 := Round ((Side_1 - 3) * Random (Rand_num) + 1) ;
  89.   X_pos_2 := Round ((Side_2 - 3) * Random (Rand_num) + Max_X - Side_2 + 1) ;
  90.   Wind_vel := Round (2 * Max_wind * Random (Rand_num) - Max_wind) ;
  91.  
  92.   { Display initial layout and initialize "Ground" values }
  93.   Conact (0) ;
  94.   FOR X := 0 TO (Side_1 - 1) DO
  95.     BEGIN
  96.       Y := Level_1 ;
  97.       GotoXY (X, (Max_Y - Y)) ;
  98.       Write (Grnd_sym) ;
  99.       Ground [X] := Y ;
  100.     END ;
  101.   FOR X := 0 TO (Center DIV 2 - 1) DO
  102.     BEGIN
  103.       Y := Round (Level_1 + (Center_ht - Level_1) * (X + 1) / (Center / 2)) ;
  104.       GotoXY ((X + Side_1), (Max_Y - Y)) ;
  105.       Write (Grnd_sym) ;
  106.       Ground [X + Side_1] := Y ;
  107.     END ;
  108.   FOR X := 0 TO (Center DIV 2 - 1) DO
  109.     BEGIN
  110.       Y := Center_ht - Round ((Center_ht - Level_2) * (X + 1) / (Center / 2)) ;
  111.       GotoXY ((X + Side_1 + Center DIV 2), (Max_Y - Y)) ;
  112.       Write (Grnd_sym) ;
  113.       Ground [X + Side_1 + Center DIV 2] := Y ;
  114.     END ;
  115.   FOR X := 0 TO (Side_2 - 1) DO
  116.     BEGIN
  117.       Y := Level_2 ;
  118.       GotoXY ((X + Side_1 + Center), (Max_Y - Y)) ;
  119.       Write (Grnd_sym) ;
  120.       Ground [X + Side_1 + Center] := Y ;
  121.     END ;
  122.  
  123.   { Show location of both players' bunkers }
  124.   GotoXY (X_pos_1 - 1, (Max_Y - Ground [X_pos_1])) ;
  125.   Write ('[1]') ;
  126.   GotoXY (X_pos_2 - 1, (Max_Y - Ground [X_pos_2])) ;
  127.   Write ('[2]') ;
  128.  
  129.   GotoXY (0, (Max_Y + 2)) ;
  130.   Conact (1) ;
  131.   Write ('Wind is to the ') ;
  132.   IF Wind_vel <= 0 THEN
  133.     Write ('LEFT ')
  134.   ELSE
  135.     Write ('RIGHT ') ;
  136.   Write ('at ', Abs (Wind_vel) : 2, ' meters/sec; ') ;
  137.   Write ('each bar (-) is ', Scale : 3, ' meters.') ;
  138.  
  139.   GotoXY (0, Max_Y + 3) ;
  140.   Conact (1) ;
  141.   Write ('When prompted, enter angle (degrees) and velocity (meters/sec)') ;
  142.   Write (', or 0 0 to quit.') ;
  143.  
  144.   GotoXY (0, (Max_Y - Level_1 + 1)) ;
  145.   Write ('Player #1: ') ;
  146.   GotoXY ((Side_1 + Center), (Max_Y - Level_2 + 1)) ;
  147.   Write ('Player #2: ') ;
  148.  
  149.   FOR X := 1 TO 2 DO
  150.     Direct_hit [X] := False ;
  151.   Quit := False ;
  152.  
  153. END ; { Set_Up_Game }
  154.  
  155.  
  156. PROCEDURE Fire (Player : Integer) ;
  157.  
  158.   LABEL
  159.     0 ;
  160.  
  161.   CONST
  162.     Spaces    = 11 ;
  163.     Pi          = 3.14159 ;
  164.     Half_cir  = 180 ; { Number of degrees equal to "Pi" radians }
  165.     Time_int  = 100 ;
  166.  
  167.   VAR
  168.     Last_X, Last_Y,
  169.     Next_X, Next_Y,
  170.     X_vel, Y_vel,
  171.     Angle, Init_vel : Real ;
  172.     N, Loc_X, Loc_Y : Integer ;
  173.     Hit, On_screen  : Boolean ;
  174.  
  175. FUNCTION Wind_Fac (X_pos, Y_pos : Real) : Real ;
  176.  
  177.   CONST
  178.     Wind_pct  = 0.1 ; { "Coupling factor" between wind and projectile }
  179.  
  180.   VAR
  181.     Shielded  : Boolean ;
  182.  
  183. BEGIN { Wind_Fac }
  184.  
  185.   IF Wind_vel > 0 THEN
  186.     IF Center_ht > Level_1 THEN
  187.       Shielded := (X_pos > (Side_1 + Center DIV 2 + 1)) AND (Y_pos < Center_ht)
  188.     ELSE
  189.       Shielded := (X_pos > Side_1) AND (Y_pos < Level_1)
  190.   ELSE
  191.     IF Center_ht > Level_2 THEN
  192.       Shielded := (X_pos < (Side_1 + Center DIV 2)) AND (Y_pos < Center_ht)
  193.     ELSE
  194.       Shielded := (X_pos < (Side_1 + Center)) AND (Y_pos < Level_2) ;
  195.  
  196.   IF Shielded THEN
  197.     Wind_Fac := 0
  198.   ELSE
  199.     Wind_Fac := Wind_vel * Wind_pct ;
  200.  
  201. END { Wind_Fac } ;
  202.  
  203. BEGIN { Fire }
  204.  
  205.   IF Player = 1 THEN
  206.     GotoXY (Spaces, (Max_Y - Level_1 + 1))
  207.   ELSE
  208.     GotoXY ((Side_1 + Center + Spaces), (Max_Y - Level_2 + 1)) ;
  209.   Read (Angle, Init_vel) ;
  210.  
  211.   { Routine for early termination of game by either player }
  212.   IF (Angle <= 0) OR (Init_vel <= 0) THEN
  213.     BEGIN
  214.       Quit := True ;
  215.       Goto 0 ;
  216.     END ;
  217.  
  218.   { Set up zero-time co-ordinates and velocities }
  219.   Angle := Angle * (Pi / Half_cir) ; { Convert degrees to radians }
  220.   X_vel := Init_vel * Cos (Angle) ;
  221.   IF Player = 2 THEN
  222.     X_vel := -X_vel ;
  223.   Y_vel := Init_vel * Sin (Angle) ;
  224.   IF Player = 1 THEN
  225.     BEGIN
  226.       Last_X := X_pos_1 ;
  227.       Last_Y := Ground [X_pos_1] ;
  228.     END
  229.   ELSE
  230.     BEGIN
  231.       Last_X := X_pos_2 ;
  232.       Last_Y := Ground [X_pos_2] ;
  233.     END ;
  234.   Hit := False ;
  235.   On_screen := False ;
  236.  
  237.   REPEAT
  238.  
  239.     { Compute velocities and positions after next second of travel }
  240.     X_vel := X_vel + Wind_Fac (Last_X, Last_Y) ;
  241.     Y_vel := Y_vel - Acc_g ;
  242.     IF On_screen THEN { Erase last symbol printed during air travel }
  243.       BEGIN
  244.     GotoXY (Loc_X, (Max_Y - Loc_Y)) ;
  245.     Write (' ') ;
  246.       END ;
  247.     Next_X := Last_X + (X_vel / Scale) ;
  248.     Loc_X := Round (Next_X) ;
  249.     Next_Y := Last_Y + (Y_vel / Scale) ;
  250.     Loc_Y := Round (Next_Y) ;
  251.  
  252.     IF (Loc_Y < 0) AND NOT (Loc_X IN [0..Max_X]) THEN { Hit ground off screen }
  253.       BEGIN
  254.     Hit := True ;
  255.     Write (Chr (Bell)) ;
  256.       END
  257.     ELSE IF Loc_X IN [0..Max_X] THEN
  258.       IF Loc_Y <= Ground [Loc_X] THEN { Hit ground on screen }
  259.     BEGIN
  260.       Loc_X := Round (Last_X + (Next_X - Last_X) / (Next_Y - Last_Y)) ;
  261.       Hit := True ;
  262.       Write (Chr (Bell)) ;
  263.       IF (Abs (Loc_X - X_pos_1)) <= 1 THEN
  264.         Direct_hit [1] := True
  265.       ELSE IF (Abs (Loc_X - X_pos_2)) <= 1 THEN
  266.         Direct_hit [2] := True
  267.       ELSE
  268.         BEGIN
  269.           GotoXY (Loc_X, (Max_Y - Ground [Loc_X])) ;
  270.           Write (Burst_sym) ;
  271.         END ;
  272.     END
  273.       ELSE { Still in flight above ground }
  274.     BEGIN
  275.       On_screen := Loc_Y IN [0..Max_Y] ;
  276.       IF On_screen THEN
  277.         BEGIN
  278.           GotoXY (Loc_X, (Max_Y - Loc_Y)) ;
  279.           Write (Air_sym) ;
  280.         END
  281.       ELSE
  282.         GotoXY (Loc_X, 0) ;
  283.       FOR N := 1 TO Time_int DO { Nothing } ;
  284.         { Time delay for display }
  285.     END
  286.     ELSE
  287.       BEGIN
  288.     On_screen := False ;
  289.     GotoXY (0, (Max_Y + 3)) ;
  290.       END ;
  291.  
  292.     { Update co-ordinates for next calculation }
  293.     Last_X := Next_X ;
  294.     Last_Y := Next_Y ;
  295.  
  296.   UNTIL Hit ;
  297.   
  298. 0: { Location to jump to in order to exit procedure }
  299.  
  300. END ; { Fire }
  301.  
  302.  
  303. PROCEDURE Show_Hit ;
  304.  
  305.   CONST
  306.     End_loop = 600 ;  { Used in timing loop for longer "bell" sound }
  307.  
  308.   VAR
  309.     N : Integer ;
  310.  
  311. BEGIN { Show_Hit }
  312.  
  313.   IF Direct_hit [1] THEN
  314.     GotoXY ((X_pos_1 - 1), (Max_Y - Level_1)) 
  315.   ELSE
  316.     GotoXY ((X_pos_2 - 1), (Max_Y - Level_2)) ;
  317.   FOR N := 1 TO 3 DO
  318.     Write (Burst_sym) ;
  319.  
  320.   IF Direct_hit [1] THEN
  321.     GotoXY (0, (Max_Y - Level_1 + 1)) 
  322.   ELSE
  323.     GotoXY ((Side_1 + Center), (Max_Y - Level_2 + 1)) ;
  324.   Conact (1) ;
  325.   Write ('BLEEP!!! Wiped out!!!') ;
  326.  
  327.   FOR N := 1 TO End_loop DO
  328.     Write (Chr (Bell)) ;
  329.  
  330. END ; { Show_Hit }
  331.  
  332.  
  333. BEGIN { Main program }
  334.  
  335.   Conact (0) ;
  336.   Writeln ('Welcome to ARTILLERY BATTLE') ;
  337.   Writeln ;
  338.  
  339.   { Initialize pseudo-random-number generator }
  340.   Write ('Enter any number to start the game: ') ;
  341.   Read (Rand_num) ;
  342.  
  343.   REPEAT
  344.  
  345.     Set_Up_Game ;
  346.  
  347.     REPEAT
  348.       Fire (1) ;
  349.       IF NOT (Direct_hit [1] OR Direct_hit [2] OR Quit) THEN
  350.     Fire (2) ;
  351.     UNTIL (Direct_hit [1] OR Direct_hit [2] OR Quit) ;
  352.  
  353.     IF NOT Quit THEN
  354.       Show_Hit ;
  355.  
  356.     GotoXY (0, (Max_Y + 2)) ;
  357.     Conact (1) ;
  358.     GotoXY (0, (Max_Y + 3)) ;
  359.     Conact (1) ;
  360.     Write ('Another game (Y/n) ? ') ;
  361.     Read (Answer) ;
  362.  
  363.   UNTIL Answer IN ['N','n'] ;
  364.  
  365. END . { Main program }
  366.  (1) ;
  367.     Write ('Another game (Y/n) ? /═J*yº╚╒"P/═B.═╠*┴*∙═I."∙z│╚*:R/âσg"═╢'ß"═½╔*∙σ═*╤"∙*P/┼═ë.┴═╠*╔x2S/y2R/:æ<6#=┬┘*++"N/╔*P/═*"P/╔*P/σ═*╤*∙y═6."