Rogue 3.6 reconstruction from http://rogue.rogueforge.net/rogue36/.
[rogue-pphs.git] / main.c
1 /*
2 * @(#)main.c 3.27 (Berkeley) 6/15/81
3 *
4 * Rogue: Exploring the Dungeons of Doom
5 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
6 * All rights reserved.
7 *
8 * See the file LICENSE.TXT for full copyright and licensing information.
9 */
10
11 #include "curses.h"
12 #include <time.h>
13 #include <signal.h>
14 #include <limits.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <string.h>
18 #include "machdep.h"
19 #include "rogue.h"
20
21 int num_checks; /* times we've gone over in checkout() */
22 WINDOW *cw; /* Window that the player sees */
23 WINDOW *hw; /* Used for the help command */
24 WINDOW *mw; /* Used to store mosnters */
25
26 main(argc, argv, envp)
27 char **argv;
28 char **envp;
29 {
30 register char *env;
31 register struct linked_list *item;
32 register struct object *obj;
33 int lowtime;
34 time_t now;
35
36 md_init();
37
38 /*
39 * check for print-score option
40 */
41 if (argc == 2 && strcmp(argv[1], "-s") == 0)
42 {
43 waswizard = TRUE;
44 score(0, -1, 0);
45 exit(0);
46 }
47 /*
48 * Check to see if he is a wizard
49 */
50 if (argc >= 2 && argv[1][0] == '\0')
51 if (strcmp(PASSWD, xcrypt(md_getpass("Wizard's password: "), "mT")) == 0)
52 {
53 wizard = TRUE;
54 argv++;
55 argc--;
56 }
57
58 /*
59 * get home and options from environment
60 */
61 strncpy(home, md_gethomedir(), PATH_MAX);
62
63 strcpy(file_name, home);
64 strcat(file_name, "rogue36.sav");
65
66 if ((env = getenv("ROGUEOPTS")) != NULL)
67 parse_opts(env);
68 if (env == NULL || whoami[0] == '\0')
69 strucpy(whoami, md_getusername(md_getuid()), strlen(md_getusername(md_getuid())));
70 if (env == NULL || fruit[0] == '\0')
71 strcpy(fruit, "slime-mold");
72
73 if (too_much() && !wizard && !author())
74 {
75 printf("Sorry, %s, but the system is too loaded now.\n", whoami);
76 printf("Try again later. Meanwhile, why not enjoy a%s %s?\n",
77 vowelstr(fruit), fruit);
78 exit(1);
79 }
80
81 if (argc == 2)
82 if (!restore(argv[1], envp)) /* Note: restore will never return */
83 exit(1);
84
85 time(&now);
86 lowtime = (int) now;
87 dnum = (wizard && getenv("SEED") != NULL ?
88 atoi(getenv("SEED")) :
89 lowtime + getpid());
90 if (wizard)
91 printf("Hello %s, welcome to dungeon #%d", whoami, dnum);
92 else
93 printf("Hello %s, just a moment while I dig the dungeon...", whoami);
94 fflush(stdout);
95 seed = dnum;
96 init_player(); /* Roll up the rogue */
97 init_things(); /* Set up probabilities of things */
98 init_names(); /* Set up names of scrolls */
99 init_colors(); /* Set up colors of potions */
100 init_stones(); /* Set up stone settings of rings */
101 init_materials(); /* Set up materials of wands */
102 initscr(); /* Start up cursor package */
103
104 if (COLS < 70)
105 {
106 endwin();
107 printf("\n\nSorry, %s, but your terminal window has too few columns.\n", whoami);
108 printf("Your terminal has %d columns, needs 70.\n",COLS);
109 exit(1);
110 }
111 if (LINES < 22)
112 {
113 endwin();
114 printf("\n\nSorry, %s, but your terminal window has too few lines.\n", whoami);
115 printf("Your terminal has %d lines, needs 22.\n",LINES);
116 exit(1);
117 }
118
119
120 setup();
121 /*
122 * Set up windows
123 */
124 cw = newwin(LINES, COLS, 0, 0);
125 mw = newwin(LINES, COLS, 0, 0);
126 hw = newwin(LINES, COLS, 0, 0);
127 keypad(cw,1);
128 waswizard = wizard;
129 new_level(); /* Draw current level */
130 /*
131 * Start up daemons and fuses
132 */
133 start_daemon(doctor, 0, AFTER);
134 fuse(swander, 0, WANDERTIME, AFTER);
135 start_daemon(stomach, 0, AFTER);
136 start_daemon(runners, 0, AFTER);
137 /*
138 * Give the rogue his weaponry. First a mace.
139 */
140 item = new_item(sizeof *obj);
141 obj = (struct object *) ldata(item);
142 obj->o_type = WEAPON;
143 obj->o_which = MACE;
144 init_weapon(obj, MACE);
145 obj->o_hplus = 1;
146 obj->o_dplus = 1;
147 obj->o_flags |= ISKNOW;
148 add_pack(item, TRUE);
149 cur_weapon = obj;
150 /*
151 * Now a +1 bow
152 */
153 item = new_item(sizeof *obj);
154 obj = (struct object *) ldata(item);
155 obj->o_type = WEAPON;
156 obj->o_which = BOW;
157 init_weapon(obj, BOW);
158 obj->o_hplus = 1;
159 obj->o_dplus = 0;
160 obj->o_flags |= ISKNOW;
161 add_pack(item, TRUE);
162 /*
163 * Now some arrows
164 */
165 item = new_item(sizeof *obj);
166 obj = (struct object *) ldata(item);
167 obj->o_type = WEAPON;
168 obj->o_which = ARROW;
169 init_weapon(obj, ARROW);
170 obj->o_count = 25+rnd(15);
171 obj->o_hplus = obj->o_dplus = 0;
172 obj->o_flags |= ISKNOW;
173 add_pack(item, TRUE);
174 /*
175 * And his suit of armor
176 */
177 item = new_item(sizeof *obj);
178 obj = (struct object *) ldata(item);
179 obj->o_type = ARMOR;
180 obj->o_which = RING_MAIL;
181 obj->o_ac = a_class[RING_MAIL] - 1;
182 obj->o_flags |= ISKNOW;
183 cur_armor = obj;
184 add_pack(item, TRUE);
185 /*
186 * Give him some food too
187 */
188 item = new_item(sizeof *obj);
189 obj = (struct object *) ldata(item);
190 obj->o_type = FOOD;
191 obj->o_count = 1;
192 obj->o_which = 0;
193 add_pack(item, TRUE);
194 playit();
195 }
196
197 /*
198 * endit:
199 * Exit the program abnormally.
200 */
201
202 void
203 endit(int p)
204 {
205 fatal("Ok, if you want to exit that badly, I'll have to allow it\n");
206 }
207
208 /*
209 * fatal:
210 * Exit the program, printing a message.
211 */
212
213 fatal(s)
214 char *s;
215 {
216 clear();
217 move(LINES-2, 0);
218 printw("%s", s);
219 draw(stdscr);
220 endwin();
221 exit(0);
222 }
223
224 /*
225 * rnd:
226 * Pick a very random number.
227 */
228
229 rnd(range)
230 register int range;
231 {
232 return range == 0 ? 0 : abs(RN) % range;
233 }
234
235 /*
236 * roll:
237 * roll a number of dice
238 */
239
240 roll(number, sides)
241 register int number, sides;
242 {
243 register int dtotal = 0;
244
245 while(number--)
246 dtotal += rnd(sides)+1;
247 return dtotal;
248 }
249 /*
250 * handle stop and start signals
251 */
252
253 void
254 tstp(int p)
255 {
256 #ifdef SIGTSTP
257 signal(SIGTSTP, SIG_IGN);
258 #endif
259 mvcur(0, COLS - 1, LINES - 1, 0);
260 endwin();
261 fflush(stdout);
262 #ifdef SIGTSTP
263 signal(SIGTSTP, SIG_DFL);
264 kill(0, SIGTSTP);
265 signal(SIGTSTP, tstp);
266 #endif
267 crmode();
268 noecho();
269 clearok(curscr, TRUE);
270 touchwin(cw);
271 draw(cw);
272 flush_type(); /* flush input */
273 }
274
275 setup()
276 {
277 #ifdef SIGHUP
278 signal(SIGHUP, auto_save);
279 #endif
280 signal(SIGILL, auto_save);
281 #ifdef SIGTRAP
282 signal(SIGTRAP, auto_save);
283 #endif
284 #ifdef SIGIOT
285 signal(SIGIOT, auto_save);
286 #endif
287 #ifdef SIGEMT
288 signal(SIGEMT, auto_save);
289 #endif
290 signal(SIGFPE, auto_save);
291 #ifdef SIGBUS
292 signal(SIGBUS, auto_save);
293 #endif
294 signal(SIGSEGV, auto_save);
295 #ifdef SIGSYS
296 signal(SIGSYS, auto_save);
297 #endif
298 #ifdef SIGPIPE
299 signal(SIGPIPE, auto_save);
300 #endif
301 signal(SIGTERM, auto_save);
302 signal(SIGINT, quit);
303 #ifdef SIGQUIT
304 signal(SIGQUIT, endit);
305 #endif
306 #ifdef SIGTSTP
307 signal(SIGTSTP, tstp);
308 #endif
309
310 if (!author())
311 {
312 #ifdef SIGALRM
313 signal(SIGALRM, checkout);
314 alarm(CHECKTIME * 60);
315 #endif
316 num_checks = 0;
317 }
318
319 crmode(); /* Cbreak mode */
320 noecho(); /* Echo off */
321 }
322
323 /*
324 * playit:
325 * The main loop of the program. Loop until the game is over,
326 * refreshing things and looking at the proper times.
327 */
328
329 playit()
330 {
331 register char *opts;
332
333 /*
334 * set up defaults for slow terminals
335 */
336
337
338 if (baudrate() < 1200)
339 {
340 terse = TRUE;
341 jump = TRUE;
342 }
343
344 /*
345 * parse environment declaration of options
346 */
347 if ((opts = getenv("ROGUEOPTS")) != NULL)
348 parse_opts(opts);
349
350
351 oldpos = hero;
352 oldrp = roomin(&hero);
353 while (playing)
354 command(); /* Command execution */
355 endit(-1);
356 }
357
358 /*
359 * see if the system is being used too much for this game
360 */
361 too_much()
362 {
363 double avec[3];
364
365 if (md_getloadavg(avec) == 0)
366 return (avec[2] > (MAXLOAD / 10.0));
367 else
368 return (md_ucount() > MAXUSERS);
369 }
370
371 /*
372 * see if a user is an author of the program
373 */
374 author()
375 {
376 switch (md_getuid())
377 {
378 case AUTHORUID:
379 return TRUE;
380 default:
381 return FALSE;
382 }
383 }
384
385 int chmsg(char *fmt, ...);
386
387 void
388 checkout(int p)
389 {
390 static char *msgs[] = {
391 "The load is too high to be playing. Please leave in %d minutes",
392 "Please save your game. You have %d minutes",
393 "Last warning. You have %d minutes to leave",
394 };
395 int checktime;
396 #ifdef SIGALRM
397 signal(SIGALRM, checkout);
398 #endif
399 if (too_much())
400 {
401 if (num_checks == 3)
402 fatal("Sorry. You took to long. You are dead\n");
403 checktime = CHECKTIME / (num_checks + 1);
404 chmsg(msgs[num_checks++], checktime);
405 #ifdef SIGALRM
406 alarm(checktime * 60);
407 #endif
408 }
409 else
410 {
411 if (num_checks)
412 {
413 chmsg("The load has dropped back down. You have a reprieve.");
414 num_checks = 0;
415 }
416 #ifdef SIGALRM
417 alarm(CHECKTIME * 60);
418 #endif
419 }
420 }
421
422 /*
423 * checkout()'s version of msg. If we are in the middle of a shell, do a
424 * printf instead of a msg to avoid the refresh.
425 */
426 chmsg(char *fmt, ...)
427 {
428 va_list args;
429
430 if (in_shell)
431 {
432 va_start(args, fmt);
433 vprintf(fmt, args);
434 va_end(args);
435 putchar('\n');
436 fflush(stdout);
437 }
438 else
439 {
440 va_start(args, fmt);
441 doadd(fmt, args);
442 va_end(args);
443 endmsg();
444 }
445 }