rogue

Ken Arnold's Rogue
git clone https://git.woozle.org/neale/rogue.git

Neale Pickett  ·  2011-10-13

startup.c

  1/*
  2 * Create the layout for the new level
  3 *
  4 * @(#)startup.c	4.45 (Berkeley) 02/05/99
  5 */
  6
  7#include <ctype.h>
  8#include <curses.h>
  9#include "netprot.h"
 10
 11typedef struct spot {		/* position matrix for maze positions */
 12	int	nexits;
 13	coord	exits[4];
 14	int	used;
 15} SPOT;
 16
 17#define GOLDGRP 1
 18
 19/*
 20 * do_rooms:
 21 *	Create rooms and corridors with a connectivity graph
 22 */
 23void
 24do_rooms(void)
 25{
 26    int i;
 27    struct room *rp;
 28    THING *tp;
 29    int left_out;
 30    static coord top;
 31    coord bsze;				/* maximum room size */
 32    coord mp;
 33
 34    bsze.x = NUMCOLS / 3;
 35    bsze.y = NUMLINES / 3;
 36    /*
 37     * Clear things for a new level
 38     */
 39    for (rp = Rooms; rp < &Rooms[MAXROOMS]; rp++)
 40    {
 41	rp->r_goldval = 0;
 42	rp->r_nexits = 0;
 43	rp->r_flags = 0;
 44    }
 45    /*
 46     * Put the gone rooms, if any, on the level
 47     */
 48    left_out = rnd(4);
 49    for (i = 0; i < left_out; i++)
 50	Rooms[rnd_room()].r_flags |= ISGONE;
 51    /*
 52     * dig and populate all the rooms on the level
 53     */
 54    for (i = 0, rp = Rooms; i < MAXROOMS; rp++, i++)
 55    {
 56	/*
 57	 * Find upper left corner of box that this room goes in
 58	 */
 59	top.x = (i % 3) * bsze.x + 1;
 60	top.y = (i / 3) * bsze.y;
 61	if (rp->r_flags & ISGONE)
 62	{
 63	    /*
 64	     * Place a gone room.  Make certain that there is a blank line
 65	     * for passage drawing.
 66	     */
 67	    do
 68	    {
 69		rp->r_pos.x = top.x + rnd(bsze.x - 2) + 1;
 70		rp->r_pos.y = top.y + rnd(bsze.y - 2) + 1;
 71		rp->r_max.x = -NUMCOLS;
 72		rp->r_max.y = -NUMLINES;
 73	    } until (rp->r_pos.y > 0 && rp->r_pos.y < NUMLINES-1);
 74	    continue;
 75	}
 76	/*
 77	 * set room type
 78	 */
 79	if (rnd(10) < Level - 1)
 80	{
 81	    rp->r_flags |= ISDARK;		/* dark room */
 82	    if (rnd(15) == 0)
 83		rp->r_flags = ISMAZE;		/* maze room */
 84	}
 85	/*
 86	 * Find a place and size for a random room
 87	 */
 88	if (rp->r_flags & ISMAZE)
 89	{
 90	    rp->r_max.x = bsze.x - 1;
 91	    rp->r_max.y = bsze.y - 1;
 92	    if ((rp->r_pos.x = top.x) == 1)
 93		rp->r_pos.x = 0;
 94	    if ((rp->r_pos.y = top.y) == 0)
 95	    {
 96		rp->r_pos.y++;
 97		rp->r_max.y--;
 98	    }
 99	}
100	else
101	    do
102	    {
103		rp->r_max.x = rnd(bsze.x - 4) + 4;
104		rp->r_max.y = rnd(bsze.y - 4) + 4;
105		rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x);
106		rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y);
107	    } until (rp->r_pos.y != 0);
108	draw_room(rp);
109	/*
110	 * Put the gold in
111	 */
112	if (rnd(2) == 0 && (!Amulet || Level >= Max_level))
113	{
114	    THING *gold;
115
116	    gold = new_item();
117	    gold->o_goldval = rp->r_goldval = GOLDCALC;
118	    find_floor(rp, &rp->r_gold, FALSE, FALSE);
119	    gold->o_pos = rp->r_gold;
120	    chat(rp->r_gold.y, rp->r_gold.x) = GOLD;
121	    gold->o_flags = ISMANY;
122	    gold->o_group = GOLDGRP;
123	    gold->o_type = GOLD;
124	    attach(Lvl_obj, gold);
125	}
126	/*
127	 * Put the monster in
128	 */
129	if (rnd(100) < (rp->r_goldval > 0 ? 80 : 25))
130	{
131	    tp = new_item();
132	    find_floor(rp, &mp, FALSE, TRUE);
133	    new_monster(tp, randmonster(FALSE), &mp);
134	    give_pack(tp);
135	}
136    }
137}
138
139/*
140 * draw_room:
141 *	Draw a box around a room and lay down the floor for normal
142 *	rooms; for maze rooms, draw maze.
143 */
144void
145draw_room(struct room *rp)
146{
147    int y, x;
148
149    if (rp->r_flags & ISMAZE)
150	do_maze(rp);
151    else
152    {
153	vert(rp, rp->r_pos.x);				/* Draw left side */
154	vert(rp, rp->r_pos.x + rp->r_max.x - 1);	/* Draw right side */
155	horiz(rp, rp->r_pos.y);				/* Draw top */
156	horiz(rp, rp->r_pos.y + rp->r_max.y - 1);	/* Draw bottom */
157
158	/*
159	 * Put the floor down
160	 */
161	for (y = rp->r_pos.y + 1; y < rp->r_pos.y + rp->r_max.y - 1; y++)
162	    for (x = rp->r_pos.x + 1; x < rp->r_pos.x + rp->r_max.x - 1; x++)
163		chat(y, x) = FLOOR;
164    }
165}
166
167/*
168 * vert:
169 *	Draw a vertical line
170 */
171void
172vert(struct room *rp, int startx)
173{
174    int y;
175
176    for (y = rp->r_pos.y + 1; y <= rp->r_max.y + rp->r_pos.y - 1; y++)
177	chat(y, startx) = '|';
178}
179
180/*
181 * horiz:
182 *	Draw a horizontal line
183 */
184void
185horiz(struct room *rp, int starty)
186{
187    int x;
188
189    for (x = rp->r_pos.x; x <= rp->r_pos.x + rp->r_max.x - 1; x++)
190	chat(starty, x) = '-';
191}
192
193/*
194 * do_maze:
195 *	Dig a maze
196 */
197
198static int	Maxy, Maxx, Starty, Startx;
199
200static SPOT	Maze[NUMLINES/3+1][NUMCOLS/3+1];
201
202void
203do_maze(struct room *rp)
204{
205    SPOT *sp;
206    int starty, startx;
207    static coord pos;
208
209    for (sp = &Maze[0][0]; sp < &Maze[NUMLINES / 3][NUMCOLS / 3 + 1]; sp++)
210    {
211	sp->used = FALSE;
212	sp->nexits = 0;
213    }
214
215    Maxy = rp->r_max.y;
216    Maxx = rp->r_max.x;
217    Starty = rp->r_pos.y;
218    Startx = rp->r_pos.x;
219    starty = (rnd(rp->r_max.y) / 2) * 2;
220    startx = (rnd(rp->r_max.x) / 2) * 2;
221    pos.y = starty + Starty;
222    pos.x = startx + Startx;
223    putpass(&pos);
224    dig(starty, startx);
225}
226
227/*
228 * dig:
229 *	Dig out from around where we are now, if possible
230 */
231void
232dig(int y, int x)
233{
234    coord *cp;
235    int cnt, newy, newx, nexty, nextx;
236    static coord pos;
237    static coord del[4] = {
238	{2, 0}, {-2, 0}, {0, 2}, {0, -2}
239    };
240
241    for (;;)
242    {
243	cnt = 0;
244	for (cp = del; cp < &del[4]; cp++)
245	{
246	    newy = y + cp->y;
247	    newx = x + cp->x;
248	    if (newy < 0 || newy > Maxy || newx < 0 || newx > Maxx)
249		continue;
250	    if (flat(newy + Starty, newx + Startx) & F_PASS)
251		continue;
252	    if (rnd(++cnt) == 0)
253	    {
254		nexty = newy;
255		nextx = newx;
256	    }
257	}
258	if (cnt == 0)
259	    return;
260	accnt_maze(y, x, nexty, nextx);
261	accnt_maze(nexty, nextx, y, x);
262	if (nexty == y)
263	{
264	    pos.y = y + Starty;
265	    if (nextx - x < 0)
266		pos.x = nextx + Startx + 1;
267	    else
268		pos.x = nextx + Startx - 1;
269	}
270	else
271	{
272	    pos.x = x + Startx;
273	    if (nexty - y < 0)
274		pos.y = nexty + Starty + 1;
275	    else
276		pos.y = nexty + Starty - 1;
277	}
278	putpass(&pos);
279	pos.y = nexty + Starty;
280	pos.x = nextx + Startx;
281	putpass(&pos);
282	dig(nexty, nextx);
283    }
284}
285
286/*
287 * accnt_maze:
288 *	Account for maze exits
289 */
290void
291accnt_maze(int y, int x, int ny, int nx)
292{
293    SPOT *sp;
294    coord *cp;
295
296    sp = &Maze[y][x];
297    for (cp = sp->exits; cp < &sp->exits[sp->nexits]; cp++)
298	if (cp->y == ny && cp->x == nx)
299	    return;
300    cp->y = ny;
301    cp->x = nx;
302}
303
304/*
305 * rnd_pos:
306 *	Pick a random spot in a room
307 */
308void
309rnd_pos(struct room *rp, coord *cp)
310{
311    cp->x = rp->r_pos.x + rnd(rp->r_max.x - 2) + 1;
312    cp->y = rp->r_pos.y + rnd(rp->r_max.y - 2) + 1;
313}
314
315/*
316 * find_floor:
317 *	Find a valid floor spot in this room.  If rp is NULL, then
318 *	pick a new room each time around the loop.
319 */
320bool
321find_floor(struct room *rp, coord *cp, int limit, bool monst)
322{
323    PLACE *pp;
324    int cnt;
325    char compchar;
326    bool pickroom;
327
328    if (!(pickroom = (rp == NULL)))
329	compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR);
330    cnt = limit;
331    for (;;)
332    {
333	if (limit && cnt-- == 0)
334	    return FALSE;
335	if (pickroom)
336	{
337	    rp = &Rooms[rnd_room()];
338	    compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR);
339	}
340	rnd_pos(rp, cp);
341	pp = INDEX(cp->y, cp->x);
342	if (monst)
343	{
344	    if (pp->p_monst == NULL && step_ok(pp->p_ch))
345		return TRUE;
346	}
347	else if (pp->p_ch == compchar)
348	    return TRUE;
349    }
350}
351
352/*
353 * enter_room:
354 *	Code that is executed whenver you appear in a room
355 */
356void
357enter_room(coord *cp)
358{
359    struct room *rp;
360    THING *tp;
361    int y, x;
362    char ch;
363
364    rp = Proom = roomin(cp);
365    door_open(rp);
366    if (!(rp->r_flags & ISDARK) && !on(Player, ISBLIND))
367	for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++)
368	{
369	    move(y, rp->r_pos.x);
370	    for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++)
371	    {
372		tp = moat(y, x);
373		ch = chat(y, x);
374		if (tp == NULL)
375		    if (inch() != ch)
376			addch(ch);
377		    else
378			move(y, x + 1);
379		else
380		{
381		    tp->t_oldch = ch;
382		    if (!see_monst(tp))
383			if (on(Player, SEEMONST))
384			{
385			    standout();
386			    addch(tp->t_disguise);
387			    standend();
388			}
389			else
390			    addch(ch);
391		    else
392			addch(tp->t_disguise);
393		}
394	    }
395	}
396}
397
398/*
399 * leave_room:
400 *	Code for when we exit a room
401 */
402void
403leave_room(coord *cp)
404{
405    PLACE *pp;
406    struct room *rp;
407    int y, x;
408    char floor;
409    char ch;
410
411    rp = Proom;
412
413    if (rp->r_flags & ISMAZE)
414	return;
415
416    if (rp->r_flags & ISGONE)
417	floor = PASSAGE;
418    else if (!(rp->r_flags & ISDARK) || on(Player, ISBLIND))
419	floor = FLOOR;
420    else
421	floor = ' ';
422
423    Proom = &Passages[flat(cp->y, cp->x) & F_PNUM];
424    for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++)
425	for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++)
426	{
427	    move(y, x);
428	    switch (ch = inch())
429	    {
430		case FLOOR:
431		    if (floor == ' ' && ch != ' ')
432			addch(' ');
433		    break;
434		default:
435		    /*
436		     * to check for monster, we have to strip out
437		     * standout bit
438		     */
439		    if (isupper(toascii(ch)))
440		    {
441			if (on(Player, SEEMONST))
442			{
443			    standout();
444			    addch(ch);
445			    standend();
446			    break;
447			}
448			pp = INDEX(cp->y, cp->x);
449			addch(pp->p_ch == DOOR ? DOOR : floor);
450		    }
451	    }
452	}
453    door_open(rp);
454}