home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol080 / artil-m.pas < prev    next >
Pascal/Delphi Source File  |  1984-04-29  |  9KB  |  335 lines

  1. PROGRAM Artillery_Battle ;  { Pascal/M version }
  2.  
  3.   { *** WRITTEN BY    Jim Bearden
  4.             Cancer Center, University of Hawaii
  5.             1236 Lauhala Street
  6.             Honolulu, Hawaii 96813
  7.  
  8.     *** DATE WRITTEN    December, 1981
  9.  
  10.     *** PROGRAM SUMMARY:
  11.       This program simulates an artillery battle between two players.
  12.     The initial setup (ground elevation on each side, locations of
  13.     bunkers, height of the central "hill" or "valley", and wind
  14.     direction and velocity) is generated at random for each game.
  15.     Each player then enters the angle (in degrees above the horizontal)
  16.     and velocity (in meters per second) of his shot. Flight of the
  17.     projectile and its point of impact are displayed, as long as it
  18.     remains on the screen. This program uses only ASCII characters and
  19.     cursor positioning (no graphics capability required), so it should
  20.     be usable on any CRT terminal with an addressable cursor (presently
  21.     set up for a 24 x 80 screen size, but may be adapted to other sizes
  22.     by changing constants as shown).
  23.   }
  24.  
  25.   {$D- (Disable "Debug" option for increased speed) }
  26.  
  27.   CONST
  28.     Grnd_sym  = '-' ; { Character used to represent ground surface in profile }
  29.     Burst_sym = '*' ; { Represents point of impact on ground }
  30.     Air_sym   = '+' ; { Represents projectile in flight }
  31.     Max_X     =  79 ; { Number of screen columns - 1 }
  32.     Max_Y     =  20 ; { Number of screen lines - 4 }
  33.     Scale     = 100 ; { Number of meters represented by each screen unit } 
  34.     Max_wind  =  25 ; { Maximum allowed wind velocity, in meters/sec }
  35.     Side_1    =  25 ; { Width of level ground section on player 1's side }
  36.     Side_2    =  25 ; { Same, player 2's side }
  37.     Center    =  30 ; { Width of center ("hill" or "valley") section }
  38.       { Sum of (Side_1 + Side_2 + Center) must equal width of screen }
  39.     Acc_g     = 9.8 ; { Acceleration of normal earth gravity, in meters/sec }
  40.     Bell      =   7 ; { ASCII equivalent of "bell" sound }
  41.  
  42.   VAR
  43.     X_pos_1, X_pos_2,    { Locations (on X-axis) of bunkers of players 1 and 2 }
  44.     Level_1, Level_2,    { Heights of level ground sections on each side }
  45.     Center_ht        : 0..Max_X ;
  46.     Wind_vel        : -Max_wind..Max_wind ;
  47.     Ground        : ARRAY [0..Max_X] OF Integer ;
  48.     Direct_hit        : ARRAY [1..2] OF Boolean ;
  49.     Rnd_num        : Real ;
  50.     Answer        : Char ;
  51.     Quit        : Boolean ;
  52.  
  53. PROCEDURE Set_Up_Game ;
  54.  
  55.   VAR
  56.     X, Y : 0..Max_X ;
  57.  
  58. BEGIN { Set_Up_Game }
  59.  
  60.   { Set up initial conditions from random-number generator }
  61.   Level_1 := Round (Max_Y * Random (0) / 2) ;
  62.   Level_2 := Round (Max_Y * Random (0) / 2) ;
  63.   Center_ht := Round (Max_Y * Random (0)) ;
  64.   X_pos_1 := Round ((Side_1 - 3) * Random (0) + 1) ;
  65.   X_pos_2 := Round ((Side_2 - 3) * Random (0) + Max_X - Side_2 + 1) ;
  66.   Wind_vel := Round (2 * Max_wind * Random (0) - Max_wind) ;
  67.  
  68.   { Display initial layout and initialize "Ground" values }
  69.   Conact (0) ;
  70.   FOR X := 0 TO (Side_1 - 1) DO
  71.     BEGIN
  72.       Y := Level_1 ;
  73.       GotoXY (X, (Max_Y - Y)) ;
  74.       Write (Grnd_sym) ;
  75.       Ground [X] := Y ;
  76.     END ;
  77.   FOR X := 0 TO (Center DIV 2 - 1) DO
  78.     BEGIN
  79.       Y := Round (Level_1 + (Center_ht - Level_1) * (X + 1) / (Center / 2)) ;
  80.       GotoXY ((X + Side_1), (Max_Y - Y)) ;
  81.       Write (Grnd_sym) ;
  82.       Ground [X + Side_1] := Y ;
  83.     END ;
  84.   FOR X := 0 TO (Center DIV 2 - 1) DO
  85.     BEGIN
  86.       Y := Center_ht - Round ((Center_ht - Level_2) * (X + 1) / (Center / 2)) ;
  87.       GotoXY ((X + Side_1 + Center DIV 2), (Max_Y - Y)) ;
  88.       Write (Grnd_sym) ;
  89.       Ground [X + Side_1 + Center DIV 2] := Y ;
  90.     END ;
  91.   FOR X := 0 TO (Side_2 - 1) DO
  92.     BEGIN
  93.       Y := Level_2 ;
  94.       GotoXY ((X + Side_1 + Center), (Max_Y - Y)) ;
  95.       Write (Grnd_sym) ;
  96.       Ground [X + Side_1 + Center] := Y ;
  97.     END ;
  98.  
  99.   { Show location of both players' bunkers }
  100.   GotoXY (X_pos_1 - 1, (Max_Y - Ground [X_pos_1])) ;
  101.   Write ('[1]') ;
  102.   GotoXY (X_pos_2 - 1, (Max_Y - Ground [X_pos_2])) ;
  103.   Write ('[2]') ;
  104.  
  105.   GotoXY (0, (Max_Y + 2)) ;
  106.   Conact (1) ;
  107.   Write ('Wind is to the ') ;
  108.   IF Wind_vel <= 0 THEN
  109.     Write ('LEFT ')
  110.   ELSE
  111.     Write ('RIGHT ') ;
  112.   Write ('at ', Abs (Wind_vel), ' meters/sec; ') ;
  113.   Write ('each bar (-) is 100 meters.') ;
  114.  
  115.   GotoXY (0, Max_Y + 3) ;
  116.   Conact (1) ;
  117.   Write ('When prompted, enter angle (degrees) and velocity (meters/sec)') ;
  118.   Write (', or 0,0 to quit.') ;
  119.  
  120.   GotoXY (0, (Max_Y - Level_1 + 1)) ;
  121.   Write ('Player #1: ') ;
  122.   GotoXY ((Side_1 + Center), (Max_Y - Level_2 + 1)) ;
  123.   Write ('Player #2: ') ;
  124.  
  125.   FOR X := 1 TO 2 DO
  126.     Direct_hit [X] := False ;
  127.   Quit := False ;
  128.  
  129. END ; { Set_Up_Game }
  130.  
  131.  
  132. PROCEDURE Fire (Player : Integer) ;
  133.  
  134.   CONST
  135.     Spaces    = 11 ;
  136.     Pi          = 3.14159 ;
  137.     Time_int  = 100 ;
  138.  
  139.   VAR
  140.     Angle, Init_vel,
  141.     Last_X, Last_Y,
  142.     Next_X, Next_Y,
  143.     X_vel, Y_vel    : Real ;
  144.     N, Loc_X, Loc_Y : Integer ;
  145.     Hit, On_screen  : Boolean ;
  146.  
  147. FUNCTION Wind_Fac (X_pos, Y_pos : Real) : Real ;
  148.  
  149.   CONST
  150.     Wind_pct  = 0.1 ; { "Coupling factor" between wind and projectile }
  151.  
  152.   VAR
  153.     Shielded  : Boolean ;
  154.  
  155. BEGIN { Wind_Fac }
  156.  
  157.   IF Wind_vel > 0 THEN
  158.     IF Center_ht > Level_1 THEN
  159.       Shielded := (X_pos > (Side_1 + Center DIV 2 + 1)) AND (Y_pos < Center_ht)
  160.     ELSE
  161.       Shielded := (X_pos > Side_1) AND (Y_pos < Level_1)
  162.   ELSE
  163.     IF Center_ht > Level_2 THEN
  164.       Shielded := (X_pos < (Side_1 + Center DIV 2)) AND (Y_pos < Center_ht)
  165.     ELSE
  166.       Shielded := (X_pos < (Side_1 + Center)) AND (Y_pos < Level_2) ;
  167.  
  168.   IF Shielded THEN
  169.     Wind_Fac := 0
  170.   ELSE
  171.     Wind_Fac := Wind_vel * Wind_pct ;
  172.  
  173. END { Wind_Fac } ;
  174.  
  175. BEGIN { Fire }
  176.  
  177.   IF Player = 1 THEN
  178.     GotoXY (Spaces, (Max_Y - Level_1 + 1))
  179.   ELSE
  180.     GotoXY ((Side_1 + Center + Spaces), (Max_Y - Level_2 + 1)) ;
  181.   Read (Angle, Init_vel) ;
  182.  
  183.   { Routine for early termination of game by either player }
  184.   IF (Angle <= 0) OR (Init_vel <= 0) THEN
  185.     BEGIN
  186.       Quit := True ;
  187.       Exit (Fire) ;
  188.     END ;
  189.  
  190.   { Set up zero-time co-ordinates and velocities }
  191.   Angle := Angle * Pi / 180 ; { Convert degrees to radians }
  192.   X_vel := Init_vel * Cos (Angle) ;
  193.   IF Player = 2 THEN
  194.     X_vel := -X_vel ;
  195.   Y_vel := Init_vel * Sin (Angle) ;
  196.   IF Player = 1 THEN
  197.     BEGIN
  198.       Last_X := X_pos_1 ;
  199.       Last_Y := Ground [X_pos_1] ;
  200.     END
  201.   ELSE
  202.     BEGIN
  203.       Last_X := X_pos_2 ;
  204.       Last_Y := Ground [X_pos_2] ;
  205.     END ;
  206.   Hit := False ;
  207.   On_screen := False ;
  208.  
  209.   REPEAT
  210.  
  211.     { Compute velocities and positions after next second of travel }
  212.     X_vel := X_vel + Wind_Fac (Last_X, Last_Y) ;
  213.     Y_vel := Y_vel - Acc_g ;
  214.     IF On_screen THEN { Erase last symbol printed during air travel }
  215.       BEGIN
  216.     GotoXY (Loc_X, (Max_Y - Loc_Y)) ;
  217.     Write (' ') ;
  218.       END ;
  219.     Next_X := Last_X + (X_vel / Scale) ;
  220.     Loc_X := Round (Next_X) ;
  221.     Next_Y := Last_Y + (Y_vel / Scale) ;
  222.     Loc_Y := Round (Next_Y) ;
  223.  
  224.     IF (Loc_Y < 0) AND NOT (Loc_X IN [0..Max_X]) THEN { Hit ground off screen }
  225.       BEGIN
  226.     Hit := True ;
  227.     Write (Chr (Bell)) ;
  228.       END
  229.     ELSE IF Loc_X IN [0..Max_X] THEN
  230.       IF Loc_Y <= Ground [Loc_X] THEN { Hit ground on screen }
  231.     BEGIN
  232.       Loc_X := Round (Last_X + (Next_X - Last_X) / (Next_Y - Last_Y)) ;
  233.       Hit := True ;
  234.       Write (Chr (Bell)) ;
  235.       IF (Abs (Loc_X - X_pos_1)) <= 1 THEN
  236.         Direct_hit [1] := True
  237.       ELSE IF (Abs (Loc_X - X_pos_2)) <= 1 THEN
  238.         Direct_hit [2] := True
  239.       ELSE
  240.         BEGIN
  241.           GotoXY (Loc_X, (Max_Y - Ground [Loc_X])) ;
  242.           Write (Burst_sym) ;
  243.         END ;
  244.     END
  245.       ELSE { Still in flight above ground }
  246.     BEGIN
  247.       On_screen := Loc_Y IN [0..Max_Y] ;
  248.       IF On_screen THEN
  249.         BEGIN
  250.           GotoXY (Loc_X, (Max_Y - Loc_Y)) ;
  251.           Write (Air_sym) ;
  252.         END
  253.       ELSE
  254.         GotoXY (Loc_X, 0) ;
  255.       FOR N := 1 TO Time_int DO { Nothing } ;
  256.         { Time delay for display }
  257.     END
  258.     ELSE
  259.       BEGIN
  260.     On_screen := False ;
  261.     GotoXY (0, (Max_Y + 3)) ;
  262.       END ;
  263.  
  264.     { Update co-ordinates for next calculation }
  265.     Last_X := Next_X ;
  266.     Last_Y := Next_Y ;
  267.  
  268.   UNTIL Hit ;
  269.   
  270. END ; { Fire }
  271.  
  272.  
  273. PROCEDURE Show_Hit ;
  274.  
  275.   VAR
  276.     N : Integer ;
  277.  
  278. BEGIN { Show_Hit }
  279.  
  280.   IF Direct_hit [1] THEN
  281.     GotoXY ((X_pos_1 - 1), (Max_Y - Level_1)) 
  282.   ELSE
  283.     GotoXY ((X_pos_2 - 1), (Max_Y - Level_2)) ;
  284.   FOR N := 1 TO 3 DO
  285.     Write (Burst_sym) ;
  286.  
  287.   IF Direct_hit [1] THEN
  288.     GotoXY (0, (Max_Y - Level_1 + 1)) 
  289.   ELSE
  290.     GotoXY ((Side_1 + Center), (Max_Y - Level_2 + 1)) ;
  291.   Conact (1) ;
  292.   Writeln ('BLEEP!!! Wiped out!!!') ;
  293.  
  294.   FOR N := 1 TO 200 DO
  295.     Write (Chr (Bell)) ;
  296.  
  297. END ; { Show_Hit }
  298.  
  299.  
  300. BEGIN { Main program }
  301.  
  302.   Conact (0) ;
  303.   Writeln ('Welcome to ARTILLERY BATTLE') ;
  304.   Writeln ;
  305.  
  306.   { Routine to randomize pseudo-random-number generator }
  307.   Write ('Press any key to start the game: ') ;
  308.   WHILE Filebusy (Keyboard) DO
  309.     Rnd_num := Random (0) ;
  310.   Read (Keyboard, Answer) ;
  311.  
  312.   REPEAT
  313.  
  314.     Set_Up_Game ;
  315.  
  316.     REPEAT
  317.       Fire (1) ;
  318.       IF NOT (Direct_hit [1] OR Direct_hit [2] OR Quit) THEN
  319.     Fire (2) ;
  320.     UNTIL (Direct_hit [1] OR Direct_hit [2] OR Quit) ;
  321.  
  322.     IF NOT Quit THEN
  323.       Show_hit ;
  324.  
  325.     GotoXY (0, (Max_Y + 2)) ;
  326.     Conact (1) ;
  327.     GotoXY (0, (Max_Y + 3)) ;
  328.     Conact (1) ;
  329.     Write ('Another game (Y/n) ? ') ;
  330.     Read (Answer) ;
  331.  
  332.   UNTIL Answer IN ['N','n'] ;
  333.  
  334. END . { Main program }
  335.