[alt.sources] An unusual skiing simulation game

stevans@resumix.UUCP (Mark Stevans) (10/26/90)

This article contains a shell archive, which in turn contains the source for
the game "Ski!".  I cannot post to "comp.sources.games", since my site does not
have the moderator's mail path.  If anyone would mail me the moderator's path,
I would really appreciate it.  Thanks.

#!/bin/sh
# This is a shell archive containing the following files: README ski.6 ski.man ski.h ski.c do_level.c makefile
# just pipe this file through /bin/sh to extract its contents
sed 's/^X//' << 'SHAR_EOF' > README
XThis directory should contain the official distribution of Ski!  Version 6.0
Xdated October 14, 1990; copyright 1990 by Mark Stevans for Roy's Games, Inc..
X
XThe command "make" should compile the game without modification under most UNIX
Xenvironments.
X
XIf the random number generator functions "srandom" and "random" do not exist,
Xthe older random number generator functions "srand" and "rand" may be
Xsubstituted in "ski.h".
X
XThe raw "nroff -man" manual pages may be found in "ski.6", and the
Xpre-formatted equivalents in "ski.man".
X
XAddress all correspondence to resumix!stevans@decwrl.dec.com
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > ski.6
X.TH SKI 6 "14 October 1990"
X.SH NAME
Xski \- an unusual skiing simulation game
X.SH SYNOPSIS
X.B ski
X.SH DESCRIPTION
XThis document describes
X.B
XSki!
XVersion 6.0 of October 14, 1990.
X.LP
XImagine you are skiing down an
Xinfinite
Xslope, facing such hazards as
Xtrees, ice, bare ground, and the Snoman! -- a horrible
Xmonster!  Each turn moves you one screen row downhill.  Unfortunately, you
Xhave to put your jet-powered skis on backwards, so you can't see ahead where
Xyou are going;
Xonly behind where you have been.
X.LP
XHowever, you can turn to either side, jump or hop through the air,
Xteleport through hyperspace, launch nuclear ICBMs, and cast spells to call the
XFire Demon.  And since the hazards occur in patches, you can skillfully
Xout-maneuver them.
X.LP
XYou ski until something bad happens to you.  Your final score is based on
Xhow far you have skiied, how many jumps you made, how many Snomen have melted
Xduring your run, and how healthy you are when are finished.
X.LP
XThese characters represent the things that you see on the slope behind you:
X.LP
X.IP I
XThis is where you are.
X.IP "."
XThis is normal snow -- always completely safe to ski on.
X.IP "Y"
XThese are trees.  If you try to ski through trees, you might hit one and get
Xhurt!
X.IP "' '"
XA space represents bare ground with no snow on it.  If you try to ski on dirt,
Xyou could fall down....
X.IP "#"
XThis is ice.  When you are on ice, you can't turn, and you might slip and
Xfall down.
X.IP "A"
XThis is the Snoman!  As soon as he crawls out of a Snobank, he will lumber
Xdirectly towards you at one space per
Xturn, and if he gets within one space of you, he will grab you and
Xbeat you up!  However, he has trouble moving through trees.  Steer clear
Xfrom the Snoman, and he will melt after a
Xwhile, since it is a sunny day.  If you jump over him, your jet-powered skis
Xwill help melt him.  You can also melt him with nuclear ICBMs,
Xor call the Fire Demon who will cook him, but once a Snoman melts, another
Xone always shows up after a while.  The Snoman doesn't understand about the
Xedges of the slope either, so you can just cross them to get away from him!
XAnd since he is slower than you, you can try to ski right past him before he
Xcan grab you!
X.IP "*"
XThis represents a nuclear ICBM that you launched.  You launch them from your
Xbackpack,
Xand they zoom right at the Snoman.
X.IP "D"
XThis is the Fire Demon, who is always your friend unless you call him a bad
Xname and he gets mad at you.
X.LP
XThese are your commands.  You can type any one of these letters
Xwhen you have the "?" prompt on the
Xend of the slope line, or just hit a return to do nothing this turn.
X.IP R
XTurn to the right.  If you were going straight down, this will make you go
Xone space to the right every turn.  If you type "R" again, then you
Xwill go two spaces to the right every turn.  If you type "L" the next
Xturn, you will again be going one space to the right every turn.
XRemember that you can't turn when you are on ice, and if you go off the edge
Xof the slope you
Xcome back into the other edge.  You travel farther while you are going
Xsideways, so you get a better score if you slalom to the side a lot,
Xbut you can never go sideways more than five spaces per turn.
X.IP L
XTurn left.  Exactly the same as turning right, but totally opposite.
X.IP J
XJump.  When jumping, you don't have the "?" on the right for each
Xline you jump over, so you can't enter a command for it.  You can't
Xfall, hit trees, or get grabbed by the Snoman while jumping, but
Xyou might land badly and get hurt.
XSince the Snoman moves one space toward you each turn, you
Xhave to be going at least two spaces per turn sideways to jump
Xover him without getting grabbed when you land, but your jet-powered
Xskis may melt the Snoman while you're jumping over him.
X.IP H
XHop.  A hop is half a jump.
X.IP T
XTeleport through hyperspace.  This transports you to somewhere else on the
Xslope, but you might materialize way up in the air and fall down.
X.IP I
XLaunch ICBM with nuclear warhead.  If your backpack is working well,
Xan ICBM will be launched from it towards the Snoman, travelling at
Xthree spaces per turn.  Launching ICBMs is dangerous, but once one is
Xgoing, it can't hurt you.  If it is launched and loses its negative-infrared
Xlock on the Snoman, it self-destructs.
X.IP D
XCast spell to bring the Fire Demon to this material plane.
XIf the alternate universes
Xare in a synchronous phase, the Fire Demon will appear somewhere on the slope,
Xand move to attack the Snoman at one space per turn, but if 
Xsomething goes wrong while casting this spell, the Fire Demon might get mad and
Xdecide to go for you instead of the Snoman!  If there is no
XSnoman around, the Fire Demon will soon get bored and go home.
XIf you don't like where the Fire Demon showed up, you can try to recast this
Xspell, so that he will appear somewhere else.
X.LP
XCorrespondence: resumix!stevans@decwrl.dec.com
X.LP
XGood luck, and happy skiing!
X.SH AUTHOR
XMark Stevans, for Roy's Games, Inc.
X.SH DIAGNOSTICS
XNone.
X.SH BUGS
XNone known.
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > ski.man
X
X
X
XSKI(6)                   GAMES AND DEMOS                   SKI(6)
X
X
X
XNAME
X     ski - an unusual skiing simulation game
X
XSYNOPSIS
X     ski
X
XDESCRIPTION
X     This document describes Ski!  Version  6.0  of  October  14,
X     1990.
X
X     Imagine you are skiing down an infinite slope,  facing  such
X     hazards  as  trees,  ice,  bare ground, and the Snoman! -- a
X     horrible monster!   Each  turn  moves  you  one  screen  row
X     downhill.   Unfortunately,  you have to put your jet-powered
X     skis on backwards, so you can't  see  ahead  where  you  are
X     going; only behind where you have been.
X
X     However, you can turn to either side, jump  or  hop  through
X     the  air, teleport through hyperspace, launch nuclear ICBMs,
X     and cast spells to call  the  Fire  Demon.   And  since  the
X     hazards  occur  in  patches, you can skillfully out-maneuver
X     them.
X
X     You ski until something bad  happens  to  you.   Your  final
X     score  is  based  on how far you have skiied, how many jumps
X     you made, how many Snomen have melted during your  run,  and
X     how healthy you are when are finished.
X
X     These characters represent the things that you  see  on  the
X     slope behind you:
X
X     I    This is where you are.
X
X     .    This is normal snow -- always completely  safe  to  ski
X          on.
X
X     Y    These are trees.  If you try to ski through trees,  you
X          might hit one and get hurt!
X
X     ' '  A space represents bare ground with no snow on it.   If
X          you try to ski on dirt, you could fall down....
X
X     #    This is ice.  When you are on ice, you can't turn,  and
X          you might slip and fall down.
X
X     A    This is the Snoman!  As soon as  he  crawls  out  of  a
X          Snobank,  he  will  lumber  directly towards you at one
X          space per turn, and if he gets within one space of you,
X          he  will  grab  you  and  beat you up!  However, he has
X          trouble moving through trees.   Steer  clear  from  the
X          Snoman,  and  he will melt after a while, since it is a
X          sunny day.  If you jump over him, your jet-powered skis
X
X
X
XSun Release 4.1   Last change: 14 October 1990                  1
X
X
X
X
X
X
XSKI(6)                   GAMES AND DEMOS                   SKI(6)
X
X
X
X          will help melt him.  You can also melt him with nuclear
X          ICBMs, or call the Fire Demon who will  cook  him,  but
X          once  a Snoman melts, another one always shows up after
X          a while.  The Snoman doesn't understand about the edges
X          of  the slope either, so you can just cross them to get
X          away from him!  And since he is slower  than  you,  you
X          can try to ski right past him before he can grab you!
X
X     *    This represents a nuclear ICBM that you launched.   You
X          launch  them from your backpack, and they zoom right at
X          the Snoman.
X
X     D    This is the Fire  Demon,  who  is  always  your  friend
X          unless you call him a bad name and he gets mad at you.
X
X     These are your commands.  You can  type  any  one  of  these
X     letters when you have the "?" prompt on the end of the slope
X     line, or just hit a return to do nothing this turn.
X
X     R    Turn to the right.  If you were  going  straight  down,
X          this  will  make  you  go  one space to the right every
X          turn.  If you type "R" again,  then  you  will  go  two
X          spaces  to  the  right every turn.  If you type "L" the
X          next turn, you will again be going  one  space  to  the
X          right  every  turn.   Remember that you can't turn when
X          you are on ice, and if you go off the edge of the slope
X          you  come back into the other edge.  You travel farther
X          while you are going sideways, so you get a better score
X          if  you  slalom to the side a lot, but you can never go
X          sideways more than five spaces per turn.
X
X     L    Turn left.  Exactly the  same  as  turning  right,  but
X          totally opposite.
X
X     J    Jump.  When jumping, you don't  have  the  "?"  on  the
X          right for each line you jump over, so you can't enter a
X          command for it.  You can't  fall,  hit  trees,  or  get
X          grabbed by the Snoman while jumping, but you might land
X          badly and get hurt.  Since the Snoman moves  one  space
X          toward you each turn, you have to be going at least two
X          spaces per turn sideways to jump over him without  get-
X          ting  grabbed  when you land, but your jet-powered skis
X          may melt the Snoman while you're jumping over him.
X
X     H    Hop.  A hop is half a jump.
X
X     T    Teleport through hyperspace.  This  transports  you  to
X          somewhere  else on the slope, but you might materialize
X          way up in the air and fall down.
X
X     I    Launch ICBM with nuclear warhead.  If your backpack  is
X          working  well, an ICBM will be launched from it towards
X
X
X
XSun Release 4.1   Last change: 14 October 1990                  2
X
X
X
X
X
X
XSKI(6)                   GAMES AND DEMOS                   SKI(6)
X
X
X
X          the  Snoman,  travelling  at  three  spaces  per  turn.
X          Launching ICBMs is dangerous, but once one is going, it
X          can't hurt you.   If  it  is  launched  and  loses  its
X          negative-infrared   lock   on   the  Snoman,  it  self-
X          destructs.
X
X     D    Cast spell to bring the Fire  Demon  to  this  material
X          plane.  If the alternate universes are in a synchronous
X          phase, the Fire Demon  will  appear  somewhere  on  the
X          slope,  and  move to attack the Snoman at one space per
X          turn, but if something goes wrong  while  casting  this
X          spell,  the  Fire  Demon might get mad and decide to go
X          for you instead of the Snoman!  If there is  no  Snoman
X          around, the Fire Demon will soon get bored and go home.
X          If you don't like where the Fire Demon showed  up,  you
X          can  try  to  recast this spell, so that he will appear
X          somewhere else.
X
X     Correspondence: resumix!stevans@decwrl.dec.com
X
X     Good luck, and happy skiing!
X
XAUTHOR
X     Mark Stevans, for Roy's Games, Inc.
X
XDIAGNOSTICS
X     None.
X
XBUGS
X     None known.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XSun Release 4.1   Last change: 14 October 1990                  3
X
X
X
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > ski.h
X/*                                  S K I !
X**
X**                       Version 6.0 of October 14, 1990
X**
X**           Copyright 1983-1990 by Mark Stevans for Roy's Games, Inc.
X*/
X
X/*
X** Utility macros.
X*/
X
X#define EOS	'\0'
X#define NIL(X)	((X) NULL)
X
X#define PUBLIC
X#define PRIVATE		static
X
X#define SUCCESS		0
X#define FAILURE		-1
X
X#define NO_POSITION	-1
X#define PROB(X)		(((RANDOM_GENERATE() % 10000) / 100.0) <= (X))
X#define ABS(X)		(((X) >= 0) ? (X) : - (X))
X#define EXISTS(X)	((X) >= 0)
X
X/*
X** The representations used for each object.
X*/
X
X#define REP_SNOW	'.'
X#define REP_TREE	'Y'
X#define REP_PLAYER	'I'
X#define REP_GROUND	' '
X#define REP_ICE		'#'
X#define REP_SNOMAN	'A'
X#define REP_ICBM	'*'
X#define REP_DEMON	'D'
X
X/*
X** "LINE_LEN" defines the length of a screen line.
X*/
X
X#define LINE_LEN				70
X
X/*
X** "MIN_SNOMAN_APPEARANCE_DISTANCE" is the minimum distance from the player
X** at which a new Snoman may appear.
X*/
X
X#define MIN_SNOMAN_APPEARANCE_DISTANCE		3
X
X/*
X** "LEVEL_MULTIPLIER" is a constant multiplied into the first element of the
X** cellular growth automaton probability array with each passing level.
X*/
X
X#define LEVEL_MULTIPLIER			1.01
X
X/*
X** "MAX_HORIZONTAL_PLAYER_SPEED" defines the absolute value of the maximum
X** horizontal player speed.
X*/
X
X#define MAX_HORIZONTAL_PLAYER_SPEED			5
X
X/*
X** "PROB_SKIS_MELT_SNOMAN" is the probability that the player's jet-powered
X** skis will melt the Snoman during each turn in which the player is jumping
X** over the Snoman.
X*/
X
X#define PROB_SKIS_MELT_SNOMAN			20.0
X
X/*
X** "PROB_SPONTANEOUS_MELT" is the probability that the Snoman melts
X** spontaneously during any given turn.
X*/
X
X#define PROB_SPONTANEOUS_MELT			1.0
X
X/*
X** "ICBM_SPEED" is the horizontal speed of an ICBM.
X*/
X
X#define ICBM_SPEED		3
X
X/*
X** "ICBM_RANGE" is the horizontal Snoman lethality range of the ICBM.
X*/
X
X#define ICBM_RANGE		2
X
X/*
X** "DEMON_RANGE" is the horizontal Snoman lethality range of the demon.
X*/
X
X#define DEMON_RANGE		1
X
X/*
X** "ICBM_SPEED" is the maximum horizontal speed of an ICBM.
X*/
X
X#define DEMON_SPEED		1
X
X/*
X** "PROB_BAD_SPELL" is the probability that the "Incant Fire Demon" spell will
X** be bad during each incantation.
X*/
X
X#define PROB_BAD_SPELL		10.0
X
X/*
X** "PROB_BAD_TELEPORT" is the probability that the teleportation device will
X** fail to safely teleport the player during each application.
X*/
X
X#define PROB_BAD_TELEPORT	10.0
X
X/*
X** "PROB_BAD_ICBM" is the probability that a nuclear ICBM will detonate in
X** the player's backpack during each launch.
X*/
X
X#define PROB_BAD_ICBM		30.0
X
X/*
X** "PROB_SLIP_ON_ICE" is the probability that the player will slip on the ice
X** and fall down for each turn during which the player is skiiing on ice.
X*/
X
X#define PROB_SLIP_ON_ICE	2.0
X
X/*
X** "PROB_FALL_ON_GROUND" is the probability that the player will fall down
X** for each turn during which the player is skiiing on bare ground.
X*/
X
X#define PROB_FALL_ON_GROUND	10.0
X
X/*
X** "PROB_HIT_TREE" is the probability that the player will hit a tree in
X** each turn during which the player is skiiing past a tree.
X*/
X
X#define PROB_HIT_TREE		25.0
X
X/*
X** "PROB_BAD_LANDING" is the probability that the player will land badly and
X** fall down during a landing from a jump or hop.
X*/
X
X#define PROB_BAD_LANDING	3.0
X
X/*
X** "POINTS_PER_JUMP" is the number of points awarded to the player for the
X** successful completion of one jump.  For scoring purposes, a hop is
X** considered to consist of exactly one half-jump.
X*/
X
X#define POINTS_PER_JUMP			20.0
X
X/*
X** "POINTS_PER_METER" is the number of points awarded to the player for each
X** meter of horizontal or vertical motion during each turn.
X*/
X
X#define POINTS_PER_METER		1.0
X
X/*
X** "POINTS_PER_MELTED_SNOMAN" is the number of points awarded to the player
X** for each Snoman that melts during the course of the game, irregardless of
X** whether the player passively caused the Snoman to melt by luring him from a
X** Snobank, or actively melted the Snoman using his skis, an ICBM, or with
X** the assistance of the Fire Demon.
X*/
X
X#define POINTS_PER_MELTED_SNOMAN	100.0
X
X/*
X** "POINTS_PER_INJURY_DEGREE"
X*/
X
X#define POINTS_PER_INJURY_DEGREE	-40.0
X
X/*
X** The injury categories.
X*/
X
X#define SLIGHT_INJURY		0
X#define MODERATE_INJURY		3
X#define SEVERE_INJURY		6
X
X/*
X** The randomness of injury degrees.
X*/
X
X#define INJURY_RANDOMNESS	6
X
X/*
X** "LEVEL" describes a playing level.
X*/
X
Xtypedef struct {
X	short meters_travelled;
X	short jump_count;
X	short level_num;
X	short num_snomen_melted;
X	float num_jumps_attempted;
X	short player_pos;
X	short snoman_pos;
X	short icbm_pos;
X	short demon_pos;
X	short player_speed;
X	char slope[LINE_LEN + 1];
X} LEVEL;
X
X/*
X** Declarations of common library functions.
X*/
X
Xextern long time();
X
X/*
X** Random number generator definitions
X*/
X
X#ifdef USE_RAND
X
Xextern int rand();
X
X#define RANDOM_INITIALIZE	srand
X#define RANDOM_GENERATE		rand
X
X#else
X
Xextern long random();
X
X#define RANDOM_INITIALIZE	srandom
X#define RANDOM_GENERATE		random
X
X#endif
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > ski.c
X/*                                  S K I !
X**
X**                       Version 6.0 of October 14, 1990
X**
X**           Copyright 1983-1990 by Mark Stevans for Roy's Games, Inc.
X*/
X
X#include <stdio.h>
X#include <ctype.h>
X#include "ski.h"
X
X/*
X**
X** Constants controlling the multiple cellular growth automatons that are
X** executed in parallel to generate hazards.
X**
X** Each cellular growth automaton probability element tends to control a
X** different facet of hazard generation:
X**
X**    [0] appearance of new hazards in clear snow
X**    [1] hazards edge growth
X**    [2] hazards edge stability
X**    [3] appearance of holes in solid hazards (this allows the Snoman to
X**        work his way through forests)
X*/
X
XPRIVATE float prob_tree[] = { 0.0, 30.0, 70.0, 90.0 };
XPRIVATE float prob_ice[] = { 0.0, 30.0, 70.0, 90.0 };
XPRIVATE float prob_ground[] = { 0.0, 30.0, 70.0, 90.0 };
XPRIVATE float prob_snoman_appearance;
X
X/*
X** "init" performs various initialization functions.
X*/
X
XPRIVATE int init(level_ptr)
XLEVEL *level_ptr;
X{
X	register int i;
X
X	/*
X	** Print the game version.
X	*/
X
X	printf("SKI!  Version 6.0!\n");
X
X	/*
X	** Initialize the random number generator.
X	*/
X
X	RANDOM_INITIALIZE((int) time(NIL(long *)));
X
X	/*
X	** Initialize the player's position.
X	*/
X
X	level_ptr->player_pos = RANDOM_GENERATE() % LINE_LEN;
X
X	/*
X	** Initialize the current level.
X	*/
X
X	for (i = 0; i < LINE_LEN; ++i)
X		level_ptr->slope[i] = REP_SNOW;
X
X	level_ptr->slope[LINE_LEN] = EOS;
X
X	level_ptr->meters_travelled = 0;
X	level_ptr->jump_count = -1;
X	level_ptr->level_num = 0;
X	level_ptr->num_snomen_melted = 0;
X	level_ptr->num_jumps_attempted = 0.0;
X	level_ptr->player_pos = RANDOM_GENERATE() % LINE_LEN;
X	level_ptr->snoman_pos = NO_POSITION;
X	level_ptr->icbm_pos = NO_POSITION;
X	level_ptr->demon_pos = NO_POSITION;
X	level_ptr->player_speed = 0;
X
X	/*
X	** Randomize the appearance probabilities.
X	*/
X
X	prob_tree[0] = (RANDOM_GENERATE() % 100) / 500.0 + 0.05;
X	prob_ice[0] = (RANDOM_GENERATE() % 100) / 500.0 + 0.05;
X	prob_ground[0] = (RANDOM_GENERATE() % 100) / 500.0 + 0.05;
X	prob_snoman_appearance = (RANDOM_GENERATE() % 100) / 25.0 + 1.0;
X
X	/*
X	** Return a code indicating successful completion.
X	*/
X
X	return (SUCCESS);
X}
X
X/*
X** "main" is the top level function of the game.
X*/
X
XPUBLIC int main()
X{
X	LEVEL level;
X
X	/*
X	** Initialize the game.
X	*/
X
X	if (init(&level) != SUCCESS)
X		exit(1);
X
X	/*
X	** Perform the game loop until the game is over.
X	*/
X
X	for (;;) {
X		draw_picture(&level);
X		do_user(&level);
X		manipulate_objects(&level);
X		update_level(&level);
X	}
X}
X
X/*
X** "gen_next_slope" generates the slope of the next level, dependent upon
X** the characteristics of the current level, the probabilities, and the
X** position of the player.
X*/
X
XPRIVATE int gen_next_slope(current_level, next_level)
XLEVEL *current_level;
XLEVEL *next_level;
X{
X	register int i;
X	register char *current_slope;
X	register char *next_slope;
X	register int player_pos;
X	short num_nearby_trees, num_nearby_ice, num_nearby_ground;
X
X	/*
X	** Cache some convenient values.
X	*/
X
X	current_slope = current_level->slope;
X	next_slope = next_level->slope;
X	player_pos = current_level->player_pos;
X
X	/*
X	** Generate each character of the next level.
X	*/
X
X	for (i = 0; i < LINE_LEN; ++i) {
X		/*
X		** Count the number of nearby trees, ice patches, and
X		** ground patches on the current level.
X		*/
X
X		num_nearby_trees = 0;
X		num_nearby_ice = 0;
X		num_nearby_ground = 0;
X
X		if (current_slope[i] == REP_TREE)
X			++num_nearby_trees;
X		if (current_slope[i] == REP_ICE)
X			++num_nearby_ice;
X		if (current_slope[i] == REP_GROUND)
X			++num_nearby_ground;
X
X		if (i > 0) {
X			if (current_slope[i - 1] == REP_TREE)
X				++num_nearby_trees;
X			else if (current_slope[i - 1] == REP_ICE)
X				++num_nearby_ice;
X			else if (current_slope[i - 1] == REP_GROUND)
X				++num_nearby_ground;
X		}
X
X		if (i < (LINE_LEN - 1)) {
X			if (current_slope[i + 1] == REP_TREE)
X				++num_nearby_trees;
X			else if (current_slope[i + 1] == REP_ICE)
X				++num_nearby_ice;
X			else if (current_slope[i + 1] == REP_GROUND)
X				++num_nearby_ground;
X		}
X
X		/*
X		** Generate this character of the next level based upon
X		** the characteristics of the nearby characters on the
X		** current level.
X		*/
X
X		if (PROB(prob_tree[num_nearby_trees]) &&
X				((i != player_pos) || (num_nearby_trees > 0)))
X			next_slope[i] = REP_TREE;
X		else if (PROB(prob_ice[num_nearby_ice]) &&
X				((i != player_pos) || (num_nearby_ice > 0)))
X			next_slope[i] = REP_ICE;
X		else if (PROB(prob_ground[num_nearby_ground]) &&
X				((i != player_pos) || (num_nearby_ground > 0)))
X			next_slope[i] = REP_GROUND;
X		else
X			next_slope[i] = REP_SNOW;
X	}
X
X	/*
X	** Terminate the slope string.
X	*/
X
X	next_slope[LINE_LEN] = EOS;
X
X	/*
X	** Return a code indicating successful completion.
X	*/
X
X	return (SUCCESS);
X}
X
X/*
X** "update_level" moves to the next level.
X*/
X
XPRIVATE int update_level(current_level)
XLEVEL *current_level;
X{
X	LEVEL next_level;
X
X	/*
X	** Go to the next level, and move the player.
X	*/
X
X	++current_level->level_num;
X
X	current_level->meters_travelled += ABS(current_level->player_speed) + 1;
X
X	/*
X	** Figure out the new player position based on a modulo
X	** addition.  Note that we must add the line length into the
X	** expression before taking the modulus to make sure that we
X	** are not taking the modulus of a negative integer.
X	*/
X
X	current_level->player_pos = (current_level->player_pos +
X			current_level->player_speed + LINE_LEN) % LINE_LEN;
X
X	/*
X	** Generate the updated slope.
X	*/
X
X	gen_next_slope(current_level, &next_level);
X
X	strcpy(current_level->slope, next_level.slope);
X
X	/*
X	** If the player was jumping, decrement the jump count.
X	*/
X
X	if (current_level->jump_count >= 0)
X		--current_level->jump_count;
X
X	/*
X	** If there is no Snoman, one might be created.
X	*/
X
X	if (!EXISTS(current_level->snoman_pos)) {
X		if (PROB(prob_snoman_appearance)) {
X			/*
X			** Make sure that the Snoman does not appear too
X			** close to the player.
X			*/
X
X			do {
X				current_level->snoman_pos = RANDOM_GENERATE() % LINE_LEN;
X			} while (ABS(current_level->snoman_pos -
X					current_level->player_pos) <=
X					MIN_SNOMAN_APPEARANCE_DISTANCE);
X		}
X	}
X
X	/*
X	** Increase the initial appearance probabilities of all obstacles and
X	** the Snoman.
X	*/
X
X	prob_tree[0] *= LEVEL_MULTIPLIER;
X	prob_ice[0] *= LEVEL_MULTIPLIER;
X	prob_ground[0] *= LEVEL_MULTIPLIER;
X	prob_snoman_appearance *= LEVEL_MULTIPLIER;
X
X	/*
X	** Return a code indicating successful completion.
X	*/
X
X	return (SUCCESS);
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > do_level.c
X/*                                  S K I !
X**
X**                       Version 6.0 of October 14, 1990
X**
X**           Copyright 1983-1990 by Mark Stevans for Roy's Games, Inc.
X*/
X
X#include <stdio.h>
X#include <ctype.h>
X#include "ski.h"
X
X/*
X** "injuries" contains the array of injury descriptions.
X*/
X
XPRIVATE char *injuries[] = {
X	"However, you escaped injury!", 
X	"But you weren't hurt at all!", 
X	"But you only got a few scratches.", 
X	"You received some cuts and bruises.", 
X	"You wind up with a concussion and some contusions.", 
X	"You now have a broken rib.", 
X	"Your left arm has been fractured.",
X	"You suffered a broken ankle.",
X	"You have a broken arm and a broken leg.", 
X	"You have four broken limbs and a cut!", 
X	"You broke every bone in your body!", 
X	"I'm sorry to tell you that you have been killed....",
X	NIL(char *)
X};
X
X/*
X** "draw_picture"
X*/
X
XPUBLIC int draw_picture(current_level)
XLEVEL *current_level;
X{
X	char level_picture[LINE_LEN + 1];
X
X	/*
X	** Create a picture of the current level.
X	*/
X
X	strcpy(level_picture, current_level->slope);
X
X	level_picture[current_level->player_pos] = REP_PLAYER;
X
X	if (EXISTS(current_level->snoman_pos))
X		level_picture[current_level->snoman_pos] = REP_SNOMAN;
X	if (EXISTS(current_level->icbm_pos))
X		level_picture[current_level->icbm_pos] = REP_ICBM;
X	if (EXISTS(current_level->demon_pos))
X		level_picture[current_level->demon_pos] = REP_DEMON;
X
X	/*
X	** Print the picture of the current level.
X	*/
X
X	printf("%4d %s ", current_level->level_num, level_picture);
X
X	/*
X	** Return a code indicating successful completion.
X	*/
X
X	return (SUCCESS);
X}
X
X/*
X** "do_user"
X*/
X
XPUBLIC int do_user(current_level)
XLEVEL *current_level;
X{
X	/*
X	** If we are jumping, just finish the line.  Otherwise, check for
X	** obstacles, and do a command.
X	*/
X
X	if (current_level->jump_count >= 0)
X		putchar('\n');
X	else {
X		check_obstacles(current_level);
X		do_command(current_level);
X	}
X}
X
X/*
X** "manipulate_objects"
X*/
X
XPUBLIC int manipulate_objects(current_level)
XLEVEL *current_level;
X{
X	/*
X	** If there is a Snoman, the player's jet-powered skis may melt him,
X	** or he may spontaneously melt.
X	*/
X
X	if (EXISTS(current_level->snoman_pos)) {
X		if (((ABS(current_level->snoman_pos - current_level->player_pos) <= 1) &&
X				PROB(PROB_SKIS_MELT_SNOMAN)) ||
X				PROB(PROB_SPONTANEOUS_MELT)) {
X			current_level->snoman_pos = NO_POSITION;
X			++current_level->num_snomen_melted;
X		}
X	}
X
X	/*
X	** If there is a Snoman, move him towards the player.  If there is a		** tree in the way, the Snoman is blocked.
X	*/
X
X	if (EXISTS(current_level->snoman_pos)) {
X		if (current_level->snoman_pos < current_level->player_pos) {
X			if (current_level->slope[current_level->snoman_pos + 1] != REP_TREE)
X				++current_level->snoman_pos;
X		}
X
X		else {
X			if (current_level->slope[current_level->snoman_pos - 1] != REP_TREE)
X				--current_level->snoman_pos;
X		}
X	}
X
X	/*                  
X	** If there is an ICBM, handle it.
X	*/
X
X	if (EXISTS(current_level->icbm_pos)) {
X		/*
X		** If there is a Snoman, move the ICBM towards him.  Else,
X		** self-destruct the ICBM.
X		*/
X
X		if (EXISTS(current_level->snoman_pos)) {
X			if (current_level->icbm_pos < current_level->snoman_pos)
X				current_level->icbm_pos += ICBM_SPEED;
X			else
X				current_level->icbm_pos -= ICBM_SPEED;
X		}
X		else
X			current_level->icbm_pos = NO_POSITION;
X	}
X
X	/*
X	** If there is a fire demon on the level, handle it.
X	*/
X
X	if (EXISTS(current_level->demon_pos)) {
X		/*
X		** If there is a Snoman on the current level, move the demon
X		** towards him.  Else, the demon might decide to leave.
X		*/
X
X		if (EXISTS(current_level->snoman_pos)) {
X			if (current_level->demon_pos < current_level->snoman_pos)
X				current_level->demon_pos += DEMON_SPEED;
X			else
X				current_level->demon_pos -= DEMON_SPEED;
X		}
X		else {
X			if (PROB(25.0))
X				current_level->demon_pos = NO_POSITION;
X		}
X	}
X
X	/*
X	** If there is a Snoman and an ICBM on the slope, the Snoman
X	** might get melted.
X	*/
X
X	if (EXISTS(current_level->snoman_pos) && EXISTS(current_level->icbm_pos)) {
X		if (ABS(current_level->snoman_pos - current_level->icbm_pos) <= ICBM_RANGE) {
X			current_level->icbm_pos = NO_POSITION;
X			current_level->snoman_pos = NO_POSITION;
X			++current_level->num_snomen_melted;
X		}
X	}
X
X	/*
X	** If there is a Snoman and a fire demon, he might get melted.
X	*/
X
X	if (EXISTS(current_level->snoman_pos) && EXISTS(current_level->demon_pos)) {
X		if (ABS(current_level->snoman_pos - current_level->demon_pos) <= 1) {
X			current_level->snoman_pos = NO_POSITION;
X			++current_level->num_snomen_melted;
X		}
X	}
X}
X
X/*
X** "accident" is called when the player gets into an accident, which ends the
X** game.  "msg" is the description of the accident type, and "severity" is
X** the severity.  This function should never return.
X*/
X
XPRIVATE int accident(current_level, msg, severity)
XLEVEL *current_level;
Xchar *msg;
Xshort severity;
X{
X	int degree;
X	long score;
X
X	/*
X	** Compute the degree of the player's injuries.
X	*/
X
X	degree = severity + (RANDOM_GENERATE() % INJURY_RANDOMNESS);
X
X	/*
X	** Print a message indicating the termination of the game.
X	*/
X
X	printf("\n\n%s  %s\n\n", msg, injuries[degree]);
X
X	/*
X	** Print the statistics of the game.
X	*/
X
X	printf("You skiied %d meters with %.1f jumps and melted %d Snowm%cn.\n",
X			current_level->meters_travelled,
X			current_level->num_jumps_attempted,
X			current_level->num_snomen_melted,
X			(current_level->num_snomen_melted == 1) ? 'a' : 'e');
X
X	/*
X	** Initially calculate the player's score based upon the number of
X	** meters travelled.
X	*/
X
X	score = current_level->meters_travelled * POINTS_PER_METER;
X
X	/*
X	** Add bonus points for the number of jumps completed.
X	*/
X
X	score += current_level->num_jumps_attempted * POINTS_PER_JUMP;
X
X	/*
X	** Add bonus points for each Snoman that melted during the course of
X	** the game.
X	*/
X
X	score += current_level->num_snomen_melted * POINTS_PER_MELTED_SNOMAN;
X
X	/*
X	** Subtract a penalty for the degree of injury experienced by the
X	** player.
X	*/
X
X	score += degree * POINTS_PER_INJURY_DEGREE;
X
X	/*
X	** Print the player's score.
X	*/
X
X	printf("Your score for this run is %ld.\n", score);
X
X	/*
X	** Exit the game with a code indicating successful completion.
X	*/
X
X	exit(0);
X}
X
X/*
X** "check_obstacles"
X*/
X
XPRIVATE int check_obstacles(current_level)
XLEVEL *current_level;
X{
X	short player_pos;
X	char *slope;
X
X	player_pos = current_level->player_pos;
X	slope = current_level->slope;
X
X	/*
X	** If we are just landing after a jump, we might fall down.
X	*/
X
X	if ((current_level->jump_count == 0) && PROB(PROB_BAD_LANDING))
X		accident(current_level, "Whoops!  A bad landing!",
X				SLIGHT_INJURY);
X
X	/*
X	** If there is a tree in our position, we might hit it.
X	*/
X
X	if ((slope[player_pos] == REP_TREE) && PROB(PROB_HIT_TREE))
X		accident(current_level, "Oh no!  You hit a tree!",
X				SEVERE_INJURY);
X
X	/*
X	** If there is bare ground under us, we might fall down.
X	*/
X
X	if ((slope[player_pos] == REP_GROUND) && PROB(PROB_FALL_ON_GROUND))
X		accident(current_level, "You fell on the ground!",
X				MODERATE_INJURY);
X
X	/*
X	** If we are on ice, we might slip.
X	*/
X
X	if ((slope[player_pos] == REP_ICE) && PROB(PROB_SLIP_ON_ICE))
X		accident(current_level, "Oops!  You slipped on the ice!",
X				SLIGHT_INJURY);
X
X	/*
X	** If there is a Snoman next to us, he may grab us.
X	*/
X
X	if (EXISTS(current_level->snoman_pos) &&
X			(ABS(current_level->snoman_pos - player_pos) <= 1))
X		accident(current_level, "Yikes!  The Snoman's got you!",
X				MODERATE_INJURY);
X}
X
X/*
X** "do_command" gets a command from the player and performs it.
X*/
X
XPRIVATE int do_command(current_level)
XLEVEL *current_level;
X{
X	register int player_pos;
X	char command_buf[LINE_LEN + 1];
X	short command_key;
X
X	player_pos = current_level->player_pos;
X
X	/*
X	** Print a prompt, and read a command.
X	*/
X
X	printf("? ");
X
X	fgets(command_buf, sizeof command_buf, stdin);
X
X	command_key = command_buf[0];
X
X	if (islower(command_key))
X		command_key = toupper(command_key);
X
X	switch (command_key) {
X	case 'R': /* Move right */
X		if ((current_level->slope[player_pos] != REP_ICE) &&
X				(current_level->player_speed < MAX_HORIZONTAL_PLAYER_SPEED))
X			++current_level->player_speed;
X
X		break;
X
X	case 'L': /* Move left */
X		if ((current_level->slope[player_pos] != REP_ICE) &&
X				(current_level->player_speed > -MAX_HORIZONTAL_PLAYER_SPEED))
X			--current_level->player_speed;
X
X		break;
X
X	case 'J': /* jump */
X		current_level->jump_count = (RANDOM_GENERATE() % 6) + 4;
X		current_level->num_jumps_attempted += 1.0;
X		break;
X
X	case 'H': /* Do a hop */
X		current_level->jump_count = (RANDOM_GENERATE() % 3) + 2;
X		current_level->num_jumps_attempted += 0.5;
X		break;
X
X	case 'T': /* Attempt teleportation */
X		if (PROB(PROB_BAD_TELEPORT))
X			accident(current_level,
X					"You materialized 25 feet in the air!",
X					SLIGHT_INJURY);
X
X		current_level->player_pos = RANDOM_GENERATE() % LINE_LEN;
X		break;
X
X	case 'I': /* Launch backpack ICBM */
X		if (PROB(PROB_BAD_ICBM))
X			accident(current_level,
X					"Nuclear blast in your backpack!",
X					SEVERE_INJURY);
X
X		current_level->icbm_pos = player_pos;
X		break;
X
X	case 'D': /* Incant spell for fire demon */
X		if (PROB(PROB_BAD_SPELL))
X			accident(current_level,
X					"A bad spell -- the demon grabs you!",
X					MODERATE_INJURY);
X
X		current_level->demon_pos = RANDOM_GENERATE() % LINE_LEN;
X		break;
X
X	default:
X		break;
X	}
X}
SHAR_EOF
sed 's/^X//' << 'SHAR_EOF' > makefile
XTARGETS = ski ski.man
XCFLAGS = -g
XOBJS = ski.o do_level.o
XHDRS = ski.h
XSOURCES = README ski.6 ski.man ski.h ski.c do_level.c makefile
X
Xall: $(TARGETS)
X
Xski: $(OBJS)
X	$(CC) $(CFLAGS) $(OBJS) -o $@
X
Xski.man: ski.6
X	nroff -man ski.6 > $@
X
X$(OBJS): $(HDRS)
X
Xski.shar: $(SOURCES)
X	shar $(SOURCES) > ski.shar
SHAR_EOF
# this is the last line of the shell archive