|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 21302 (0x5336) Types: TextFile Names: »pac.pas«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Pm/Apollo/pac.pas«
PROGRAM pacm; { APOLLO PAC - a pacman like game } { } { Written January, 1985 by Geoffrey Cooper } { } { Copyright (C) 1985, IMAGEN Corporation } { This software may be duplicated in part of in whole so long as [1] this } { notice is preserved in the copy, and [2] no financial gain is derived } { from the copy. Copies of this software other than as restricted above } { may be made only with the consent of the author. } %include '/sys/ins/base.ins.pas'; %include '/sys/ins/error.ins.pas'; %include '/sys/ins/kbd.ins.pas'; %include '/sys/ins/gpr.ins.pas'; %include '/sys/ins/pgm.ins.pas'; %include '/sys/ins/pad.ins.pas'; %include '/sys/ins/time.ins.pas'; %include '/sys/ins/tone.ins.pas'; %include 'fig.ins.pas'; {mobile_figure module} %include 'board.ins.pas'; {pacman_board module} PROCEDURE pacm_$refresh_all; EXTERN; PROCEDURE pacm_$noop; EXTERN; PROCEDURE pacm_$refresh_part(IN unobscured, pos_change: boolean); EXTERN; TYPE ndesc = record tip_x, tip_y: integer; base_x, base_y: integer; inc_x, inc_y: integer end; CONST pac_init_x = guage; pac_init_y = guage; nasty_init_x = guage*29; nasty_init_y = guage*32; max_nasties = 15; VAR play_forever: boolean; ndh: array[0..3] of ndesc := [ [ (guage div 2), 0, -(guage div 2), -(guage div 2), 0, 1 ], [ 0, -(guage div 2), -(guage div 2), (guage div 2), 1, 0 ], [ -(guage div 2), 0, (guage div 2), -(guage div 2), 0, 1 ], [ 0, (guage div 2), -(guage div 2), -(guage div 2), 1, 0 ] ]; screen : gpr_$bitmap_desc_t; screen_size : gpr_$offset_t; pac : DEFINE fig_$t; nasty : fig_$t; nasties : DEFINE array [1..max_nasties] of fig_$t; num_nasties : DEFINE integer; pac_time : integer32; num_pacs : integer; screen_rfs : integer; score_dots : integer; score_bigdots: integer; score : integer; clock_tick : integer32 := 20000; { 12.5 ticks per second } incs: array [1..3] of integer := [ 1, 3, 2 ]; nasty_rand : integer; last_tick : DEFINE time_$clock_t; { Initialize the display, using GPR routines } PROCEDURE pacm_$init_gpr; CONST bitmap_max_size = 1024; black_and_white = 0; keyset = [ kbd_$up_arrow, kbd_$down_arrow, kbd_$left_arrow, kbd_$right_arrow, kbd_$hold2, kbd_$l_box_arrow, kbd_$r_box_arrow, kbd_$down_box_arrow2, kbd_$up_box_arrow2, kbd_$next_win, 'f', 's', 'l', 'q' ]; buttonset = ['a', 'A', 'b', 'c']; locatorset = []; raster_op_XOR = 6; VAR attr: gpr_$attribute_desc_t; status: status_$t; unobscured: BOOLEAN; font_width, font_height, font_length, font_id: INTEGER; font_name: STRING; plane: integer; BEGIN { Initialize the a displayed bitmap filling the frame } screen_size.x_size := bitmap_max_size; screen_size.y_size := bitmap_max_size; gpr_$init( gpr_$direct, stream_$stdout, screen_size, black_and_white, screen, status ); gpr_$inq_bitmap_dimensions(screen, screen_size, plane, status); gpr_$set_obscured_opt(gpr_$block_if_obs, status); { Set up bitmap to use the default font } pad_$inq_font( stream_$stdout, font_width, font_height, font_name, sizeof(String), font_length, status ); gpr_$load_font_file( font_name, font_length, font_id, status ); gpr_$set_text_font( font_id, status ); { enable input from mouse } gpr_$enable_input( gpr_$keystroke, keyset, status); gpr_$set_raster_op(0, raster_op_XOR, status); gpr_$set_cursor_active( true, status ); END; PROCEDURE add_time( IN OUT t: time_$clock_t; ticktime: linteger ); VAR i: linteger; BEGIN i := t.low32 + ticktime; if i < t.low32 then t.high16 := t.high16 + 1; t.low32 := i END; PROCEDURE pregnant_pause; CONST ticktime = 156250; VAR t :time_$clock_t; status : status_$t; BEGIN t.high16 := 0; t.low32 := ticktime; time_$wait( time_$relative, t, status ); add_time(last_tick, ticktime) END; PROCEDURE pacm_$init_pac; VAR pac_bitmaps : fig_$orientations; pac_size : gpr_$offset_t; status : status_$t; point : gpr_$position_t; unobsc : boolean; i,j : integer; attr : gpr_$attribute_desc_t; CONST wedge_begin = (guage div 2) - (guage div 8) - 1; wedge_end = (guage div 2) + (guage div 8) + 1; BEGIN gpr_$allocate_attribute_block(attr, status); pac_size.x_size := guage; pac_size.y_size := guage; point.x_coord := guage div 2; point.y_coord := guage div 2; unobsc := gpr_$acquire_display(status); for i := 0 to 3 do begin gpr_$allocate_bitmap(pac_size, 0, attr, pac_bitmaps[i], status); gpr_$set_bitmap(pac_bitmaps[i], status); gpr_$circle_filled(point, (guage div 2) - 1, status); gpr_$set_draw_value(0, status); for j := wedge_begin to wedge_end do begin gpr_$move((guage div 2), (guage div 2), status); CASE i OF 0: gpr_$line( guage, j , status); 1: gpr_$line( j , 0 , status); 2: gpr_$line( 0 , j , status); 3: gpr_$line( j , guage, status); END end; gpr_$set_draw_value(1, status) END; fig_$create(pac_bitmaps, pac_init_x, pac_init_y, pac); fig_$set_velocity(pac, (guage div 2) + (guage div 8)); gpr_$release_display(status); END; PROCEDURE pacm_$init_nasty; CONST pi = 3.14159; right_angle = pi/2; mag = guage div 2; VAR nasty_bitmaps : fig_$orientations; size : gpr_$offset_t; status : status_$t; unobsc : boolean; i,j : integer; attr : gpr_$attribute_desc_t; org : gpr_$position_t; org0 : gpr_$position_t; angle : real; x, y : integer; x1, y1 : integer; BEGIN org.x_coord := guage div 2; org.y_coord := guage div 2; org0.x_coord := 0; org0.y_coord := 0; gpr_$allocate_attribute_block(attr, status); size.x_size := guage; size.y_size := guage; unobsc := gpr_$acquire_display(status); for i := 0 to 3 do begin gpr_$allocate_bitmap(size, 0, attr, nasty_bitmaps[i], status); gpr_$set_bitmap(nasty_bitmaps[i], status); gpr_$set_coordinate_origin(org, status); gpr_$move(ndh[i].tip_x, ndh[i].tip_y, status); for j := 0 to guage-1 do begin gpr_$line(ndh[i].base_x, ndh[i].base_y, status); gpr_$move(ndh[i].tip_x, ndh[i].tip_y, status); ndh[i].base_x := ndh[i].base_x + ndh[i].inc_x; ndh[i].base_y := ndh[i].base_y + ndh[i].inc_y end; gpr_$set_coordinate_origin(org0, status); end; fig_$create(nasty_bitmaps, nasty_init_x, nasty_init_y, nasty); fig_$set_velocity(nasty, (guage div 2)); gpr_$release_display(status); nasty_rand := 0; nasties[1] := nasty; num_nasties := 1 END; PROCEDURE pacm_$add_nasty(OUT n: fig_$t); BEGIN fig_$create(nasty^.figures, nasty_init_x, nasty_init_y, n); fig_$refresh(n); fig_$set_velocity(n, (guage div 2)); END; PROCEDURE pacm_$tick_nasty(nasty: fig_$t); { Algorithm for controlling the nasty: using absolute difference between nasty x and y positions and pac's, prefer the correct direction in each axis, with the axis with the largest distance having priority. The other two possible turns are random, except that the `about face' direction has low priority. Then: Only try all four possibilities when you have hit a wall. Only allow yourself to about face every ALLOW_REVERSE moves unless you have hit a wall. } CONST allow_reverse = 50; VAR pos: gpr_$position_t; turnpos: gpr_$position_t; i: integer; orient: integer; can_turn: boolean; no_change: boolean; bound: integer; t :time_$clock_t; turns: array[0..3] of integer; diff_x, diff_y: integer; about_face: integer; BEGIN fig_$elapse_time(nasty, 1, pos); board_$try_pac_position(pos); nasty_rand := nasty_rand + 1; no_change := pos = nasty^.position; bound := 1; if no_change then bound := 3; { find priorities for directions } diff_x := pos.x_coord - pac^.position.x_coord; diff_y := pos.y_coord - pac^.position.y_coord; if abs(diff_x) > abs(diff_y) then begin if diff_x > 0 then begin turns[0] := or$left; turns[2] := or$right end else begin turns[0] := or$right; turns[2] := or$left end; if diff_y > 0 then begin turns[1]:= or$up; turns[3] := or$down end else begin turns[1] := or$down; turns[3] := or$up end end else begin if diff_x > 0 then begin turns[1] := or$left; turns[3] := or$right end else begin turns[1] := or$right; turns[3] := or$left end; if diff_y > 0 then begin turns[0]:= or$up; turns[2] := or$down end else begin turns[0] := or$down; turns[2] := or$up end end; about_face := ((nasty^.orientation+2) mod 4); if turns[2] = about_face then begin i := turns[3]; turns[3] := turns[2]; turns[2] := i end; can_turn := false; for i := 0 to bound do begin orient := turns[i]; if no_change or else orient <> about_face or else (nasty_rand mod allow_reverse) = 0 then begin turnpos := pos; board_$can_turn(turnpos, orient, can_turn); end; if can_turn then exit end; if can_turn and then orient <> nasty^.orientation then begin fig_$turn(nasty, orient); pos := turnpos end; fig_$move(nasty, pos); { check scores } if fig_$coincident(nasty, pac) then begin num_pacs := num_pacs - 1; t.high16 := 0; t.low32 := 10000; tone_$time(t); add_time(last_tick, 10000); pos.x_coord := pac_init_x; pos.y_coord := pac_init_y; fig_$move(pac, pos); pos.x_coord := nasty_init_x; pos.y_coord := nasty_init_y; fig_$move(nasty, pos); pregnant_pause; end END; PROCEDURE pacm_$tick_all_nasties; VAR i: integer; BEGIN for i := 1 to num_nasties do pacm_$tick_nasty(nasties[i]); END; PROCEDURE pacm_$tick; VAR i : linteger; status : status_$t; unobsc : boolean; release : boolean; BEGIN add_time(last_tick, clock_tick); release := (pac_time mod 16) = 0; pac_time := pac_time + 1; if release then gpr_$release_display(status); time_$wait( time_$absolute, last_tick, status ); time_$clock(last_tick); if release then unobsc := gpr_$acquire_display(status); END; PROCEDURE pacm_$play; VAR c : char; pos : gpr_$position_t; event : gpr_$event_t; cp : ^char; status : status_$t; unobsc : boolean; wasdot : boolean; special : boolean; is_q_orient : boolean; can_turn : boolean; q_orient : board_$direction; num_dots : integer; num_bigdots : integer; total_dots : integer; total_sdots : integer; i : integer; num_events : integer; num_passes : integer32; u1, u2 : univ_ptr; BEGIN num_dots := 0; num_bigdots := 0; score_dots := 0; score_bigdots := 0; score := 0; pac_time := 0; num_pacs := 5; screen_rfs := 0; pacm_$init_gpr; pacm_$init_pac; pacm_$init_nasty; unobsc := gpr_$acquire_display(status); gpr_$set_bitmap(screen, status); u1 := addr(pacm_$refresh_part); u2 := addr(pacm_$noop); gpr_$set_refresh_entry(addr(pacm_$refresh_part), addr(pacm_$noop), status); board_$init(screen, screen_size, num_pacs); board_$get_num_dots(total_dots, total_sdots); pacm_$refresh_all; is_q_orient := false; c := chr(0); cp := addr(c); num_events := 2; num_passes := 0; REPEAT repeat unobsc := gpr_$cond_event_wait(event, c, pos, status); IF status.all <> status_$OK THEN BEGIN error_$print(status); pgm_$exit; END; IF event = gpr_$keystroke THEN CASE c OF kbd_$right_arrow: begin is_q_orient := true; q_orient := or$right end; kbd_$up_arrow: begin is_q_orient := true; q_orient := or$up end; kbd_$left_arrow: begin is_q_orient := true; q_orient := or$left end; kbd_$down_arrow: begin is_q_orient := true; q_orient := or$down end; 'f': begin clock_tick := clock_tick - 1000; if clock_tick < 0 then clock_tick := 0; end; 's': clock_tick := clock_tick + 1000; 'l': pacm_$refresh_all; kbd_$up_box_arrow2: begin if pac^.velocity < (guage-1) then fig_$set_velocity(pac, pac^.velocity+1) end; kbd_$down_box_arrow2: begin if pac^.velocity <> 0 then fig_$set_velocity(pac, pac^.velocity - 1) end; kbd_$hold2: begin repeat unobsc := gpr_$event_wait(event, c, pos, status); until (event = gpr_$keystroke) AND (c = kbd_$hold2); num_events := 2 end; 'q':; OTHERWISE { ignore other characters -- they are defined so } { that pressing them by accident doesn't spoil } { the game. } END; num_events := num_events + 1; UNTIL event <> gpr_$keystroke; { num_passes is to prevent an initial "spurt" when libraries } { are loaded the first time a pac is run in a process } num_passes := num_passes + 1; if (num_events > 1) or (num_passes < 10) then time_$clock(last_tick); num_events := 0; pacm_$tick; fig_$elapse_time(pac, 1, pos); { stop pac man at boundary } board_$try_pac_position(pos); board_$clear_dot(pos, wasdot, special); if wasdot then if special then begin num_bigdots := num_bigdots + 1; score_bigdots := score_bigdots + 1; score := score + 5; end else begin num_dots := num_dots + 1; score_dots := score_dots + 1; score := score + 1; end; board_$show_score( score, num_pacs ); if is_q_orient then begin if pac^.orientation = q_orient then is_q_orient := false else begin board_$can_turn(pos, q_orient, can_turn); if can_turn then begin fig_$turn(pac, q_orient); is_q_orient := false end end end; fig_$move(pac, pos); { move /nasty/ } pacm_$tick_all_nasties; if num_dots = total_dots THEN begin screen_rfs := screen_rfs + 1; board_$reinit; fig_$refresh(pac); for i := 1 to num_nasties do fig_$refresh(nasties[i]); num_bigdots := 0; num_dots := 0; for i := 1 to num_nasties do if nasties[i]^.velocity < (guage-1) then fig_$set_velocity(nasties[i], nasties[i]^.velocity+1); if num_nasties < max_nasties then begin num_nasties := num_nasties + 1; pacm_$add_nasty(nasties[num_nasties]) end; num_pacs := num_pacs + 1; time_$clock(last_tick); end UNTIL (c = 'q') OR ((num_pacs <= 0) AND (NOT play_forever)); { Read any extra characters that were typed but not read yet } { This is necessary since otherwise special characters can get } { left in the input stream and kill the csh } repeat unobsc := gpr_$cond_event_wait(event, c, pos, status); until (event <> gpr_$keystroke) OR (status.all <> status_$ok); gpr_$release_display(status); gpr_$terminate(false, status); i := 6 + screen_rfs - num_pacs; if num_pacs <> 0 then writeln('PAC score after ', i:0, ' pacs:') else writeln('Final PAC score (', i:0, ' pacs):'); writeln(' ', score:0, ' points, ', screen_rfs:0, ' entire screens consumed.') END; PROCEDURE pacm_$help; VAR status : status_$t; argv_ptr : pgm_$argv_ptr; argc : integer; BEGIN pgm_$get_args(argc, argv_ptr); play_forever := false; if argc = 7 then begin writeln('Pac - play forever mode.'); play_forever := true; argc := 0; end; if argc > 1 then begin writeln('pac - play pac man.'); writeln('usage: pac'); writeln('[An argument gives this help, no argument plays the game]'); writeln('PAC is an adaptation of the ever-popular ATARI game, PACMAN(C).'); writeln('You control a round PAC, which runs from the scurrying'); writeln('NASTIES. The nasties seek the PAC like heat-seeking missiles.'); writeln('When they catch it, it is destroyed, and both nasty and pac'); writeln('go to neutral corners. You start the game with five PACs.'); writeln; writeln('The PAC accumulates points by eating solid dots [1 point] and'); writeln('hollow dots [5 points]. When all the dots on the screen are'); writeln('eaten, the screen is re-filled, and you are given one more '); writeln('PAC "life." The game also gets tougher each time the screen'); writeln('refreshes, since a new nasty appears, and all existing nasties'); writeln('get a bit faster.'); writeln; writeln('Control the PAC by using the arrow keys. Pressing an'); writeln('arrow key queues a request to turn in that direction.'); writeln('The request is processed when the turn is first possible.'); writeln('For best results, do not hold down the arrow keys.'); writeln; writeln('The UP and DOWN block arrows make the PAC get slower and faster,'); writeln('respectively. A slow PAC is more maneuverable, but must'); writeln('be more strategic to escape the nasties.'); writeln; writeln('Additional commands:'); writeln(' ''q'' - quits the game immediately'); writeln(' ''l'' - manual refresh of screen'); writeln(' HOLD - stops action until you press hold again'); writeln(' POP - the game stops if the window is obscured'); writeln(' ''f'' - speed up the game clock (decrease tick time)'); writeln(' ''s'' - slow down the game clock (increase tick time)'); writeln('If you start with a window that is too small, just enlarge it.'); writeln; writeln('Run this program again without arguments to play.'); pgm_$exit end else begin writeln('Pac: type ''q'' to quit, then ''pac help'' to get instructions'); pregnant_pause; end END; BEGIN pacm_$help; pacm_$play; END.