1 //                                  S K I !
2 //
3 // Version 6.0 of October 14, 1990
4 // Copyright 1983-1990 by Mark Stevans for Roy's Games, Inc.
5 //
6 // Version 6.1 of December 30 2003
7 // Copright 2003 by Eric S. Raymond
8 
9 #include <stdio.h>
10 #include <ctype.h>
11 #ifdef CURSES
12 #include <curses.h>
13 #endif /* CURSES */
14 #ifdef NCURSES
15 #include <ncurses.h>
16 #endif /* NCURSES */
17 #include "ski.h"
18 
19 // Constants controlling the multiple cellular growth automatons that are
20 // executed in parallel to generate hazards.
21 //
22 // Each cellular growth automaton probability element tends to control a
23 // different facet of hazard generation:
24 //
25 //    [0] appearance of new hazards in clear snow
26 //    [1] hazards edge growth
27 //    [2] hazards edge stability
28 //    [3] appearance of holes in solid hazards (this allows the Snoman to
29 //        work his way through forests)
30 
31 static float prob_tree[] = { 0.0, 30.0, 70.0, 90.0 };
32 static float prob_ice[] = { 0.0, 30.0, 70.0, 90.0 };
33 static float prob_ground[] = { 0.0, 30.0, 70.0, 90.0 };
34 static float prob_snoman_appearance;
35 
init(LEVEL * level_ptr)36 static int init(LEVEL *level_ptr)
37 // Initialize the zero level
38 {
39     register int i;
40 
41     // Print the game version.
42     printf("SKI!  Version 6.1!\n");
43 
44     // Initialize the random number generator.
45     RANDOM_INITIALIZE((int) time(NIL(long *)));
46 
47     // Initialize the player's position.
48     level_ptr->player_pos = RANDOM_GENERATE() % LINE_LEN;
49 
50     // Initialize the current level.
51     for (i = 0; i < LINE_LEN; ++i)
52 	level_ptr->slope[i] = REP_SNOW;
53 
54     level_ptr->slope[LINE_LEN] = EOS;
55 
56     level_ptr->meters_travelled = 0;
57     level_ptr->jump_count = -1;
58     level_ptr->level_num = 0;
59     level_ptr->num_snomen_melted = 0;
60     level_ptr->num_jumps_attempted = 0.0;
61     level_ptr->player_pos = RANDOM_GENERATE() % LINE_LEN;
62     level_ptr->snoman_pos = NO_POSITION;
63     level_ptr->icbm_pos = NO_POSITION;
64     level_ptr->demon_pos = NO_POSITION;
65     level_ptr->player_speed = 0;
66 
67     // Randomize the appearance probabilities.
68     prob_tree[0] = (RANDOM_GENERATE() % 100) / 500.0 + 0.05;
69     prob_ice[0] = (RANDOM_GENERATE() % 100) / 500.0 + 0.05;
70     prob_ground[0] = (RANDOM_GENERATE() % 100) / 500.0 + 0.05;
71     prob_snoman_appearance = (RANDOM_GENERATE() % 100) / 25.0 + 1.0;
72 
73     // Return a code indicating successful completion.
74     return (SUCCESS);
75 }
76 
77 
gen_next_slope(LEVEL * current_level,LEVEL * next_level)78 static int gen_next_slope(LEVEL *current_level, LEVEL *next_level)
79 // Generates the slope of the next level, dependent upon
80 // the characteristics of the current level, the probabilities, and the
81 // position of the player.
82 {
83     register int i;
84     register char *current_slope;
85     register char *next_slope;
86     register int player_pos;
87     short num_nearby_trees, num_nearby_ice, num_nearby_ground;
88 
89     // Cache some convenient values.
90     current_slope = current_level->slope;
91     next_slope = next_level->slope;
92     player_pos = current_level->player_pos;
93 
94     // Generate each character of the next level.
95     for (i = 0; i < LINE_LEN; ++i) {
96 	// Count the number of nearby trees, ice patches, and
97 	// ground patches on the current level.
98 	num_nearby_trees = 0;
99 	num_nearby_ice = 0;
100 	num_nearby_ground = 0;
101 
102 	if (current_slope[i] == REP_TREE)
103 	    ++num_nearby_trees;
104 	if (current_slope[i] == REP_ICE)
105 	    ++num_nearby_ice;
106 	if (current_slope[i] == REP_GROUND)
107 	    ++num_nearby_ground;
108 
109 	if (i > 0) {
110 	    if (current_slope[i - 1] == REP_TREE)
111 		++num_nearby_trees;
112 	    else if (current_slope[i - 1] == REP_ICE)
113 		++num_nearby_ice;
114 	    else if (current_slope[i - 1] == REP_GROUND)
115 		++num_nearby_ground;
116 	}
117 
118 	if (i < (LINE_LEN - 1)) {
119 	    if (current_slope[i + 1] == REP_TREE)
120 		++num_nearby_trees;
121 	    else if (current_slope[i + 1] == REP_ICE)
122 		++num_nearby_ice;
123 	    else if (current_slope[i + 1] == REP_GROUND)
124 		++num_nearby_ground;
125 	}
126 
127 	// Generate this character of the next level based upon
128 	// the characteristics of the nearby characters on the
129 	// current level.
130 	if (PROB(prob_tree[num_nearby_trees]) &&
131 			((i != player_pos) || (num_nearby_trees > 0)))
132 		next_slope[i] = REP_TREE;
133 	else if (PROB(prob_ice[num_nearby_ice]) &&
134 			((i != player_pos) || (num_nearby_ice > 0)))
135 		next_slope[i] = REP_ICE;
136 	else if (PROB(prob_ground[num_nearby_ground]) &&
137 			((i != player_pos) || (num_nearby_ground > 0)))
138 		next_slope[i] = REP_GROUND;
139 	else
140 		next_slope[i] = REP_SNOW;
141     }
142 
143     // Terminate the slope string.
144     next_slope[LINE_LEN] = EOS;
145 
146     // Return a code indicating successful completion.
147     return (SUCCESS);
148 }
149 
update_level(current_level)150 static int update_level(current_level)
151 // Move to the next level
152 LEVEL *current_level;
153 {
154     LEVEL next_level;
155 
156     // Go to the next level, and move the player.
157     ++current_level->level_num;
158 
159     current_level->meters_travelled += ABS(current_level->player_speed) + 1;
160 
161     // Figure out the new player position based on a modulo
162     // addition.  Note that we must add the line length into the
163     // expression before taking the modulus to make sure that we
164     // are not taking the modulus of a negative integer.
165     current_level->player_pos = (current_level->player_pos +
166 		    current_level->player_speed + LINE_LEN) % LINE_LEN;
167 
168     // Generate the updated slope.
169     gen_next_slope(current_level, &next_level);
170     strcpy(current_level->slope, next_level.slope);
171 
172     // If the player was jumping, decrement the jump count.
173     if (current_level->jump_count >= 0)
174 	--current_level->jump_count;
175 
176     // If there is no Snoman, one might be created.
177     if (!EXISTS(current_level->snoman_pos)) {
178 	if (PROB(prob_snoman_appearance)) {
179 	    // Make sure that the Snoman does not appear too
180 	    // close to the player.
181 	    do {
182 		current_level->snoman_pos = RANDOM_GENERATE() % LINE_LEN;
183 	    } while (ABS(current_level->snoman_pos -
184 			 current_level->player_pos) <=
185 		     MIN_SNOMAN_APPEARANCE_DISTANCE);
186 	}
187     }
188 
189     // Increase the initial appearance probabilities of all obstacles and
190     // the Snoman.
191     prob_tree[0] *= LEVEL_MULTIPLIER;
192     prob_ice[0] *= LEVEL_MULTIPLIER;
193     prob_ground[0] *= LEVEL_MULTIPLIER;
194     prob_snoman_appearance *= LEVEL_MULTIPLIER;
195 
196     // Return a code indicating successful completion.
197     return (SUCCESS);
198 }
199 
200 // Main sequence
201 
main(int argc,char ** argv)202 int main(int argc, char **argv)
203 {
204     LEVEL level;
205 
206 #ifdef A_COLOR
207     // Initialize the color support.
208     init_colors();
209 #endif /* A_COLOR */
210 
211     // Initialize the game.
212     if (init(&level) != SUCCESS)
213 	    exit(1);
214 
215     // Perform the game loop until the game is over.
216     for (;;) {
217 	    draw_picture(&level);
218 	    do_user(&level);
219 	    manipulate_objects(&level);
220 	    update_level(&level);
221     }
222 }
223 
224 // end
225 
226 
227 
228