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