aboutsummaryrefslogtreecommitdiff
path: root/larn/create.c
diff options
context:
space:
mode:
authorB. Watson <yalhcru@gmail.com>2015-05-07 16:32:32 -0400
committerB. Watson <yalhcru@gmail.com>2015-05-07 16:32:32 -0400
commit013ac7742311556022304e8b30ca170d48b3a016 (patch)
tree53faa33e75991363f1a6dcc7edc83a66b70e6995 /larn/create.c
downloadbsd-games-extra-013ac7742311556022304e8b30ca170d48b3a016.tar.gz
initial commit
Diffstat (limited to 'larn/create.c')
-rw-r--r--larn/create.c606
1 files changed, 606 insertions, 0 deletions
diff --git a/larn/create.c b/larn/create.c
new file mode 100644
index 0000000..440b918
--- /dev/null
+++ b/larn/create.c
@@ -0,0 +1,606 @@
+/* $NetBSD: create.c,v 1.12 2012/06/19 05:30:43 dholland Exp $ */
+
+/* create.c Larn is copyrighted 1986 by Noah Morgan. */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: create.c,v 1.12 2012/06/19 05:30:43 dholland Exp $");
+#endif /* not lint */
+
+#include "header.h"
+#include "extern.h"
+#include <unistd.h>
+
+static void makemaze(int);
+static int cannedlevel(int);
+static void treasureroom(int);
+static void troom(int, int, int, int, int, int);
+static void makeobject(int);
+static void fillmroom(int, int, int);
+static void froom(int, int, int);
+static void fillroom(int, int);
+static void sethp(int);
+static void checkgen(void);
+
+/*
+ makeplayer()
+
+ subroutine to create the player and the players attributes
+ this is called at the beginning of a game and at no other time
+ */
+void
+makeplayer(void)
+{
+ int i;
+ scbr();
+ clear();
+ c[HPMAX] = c[HP] = 10; /* start player off with 15 hit points */
+ c[LEVEL] = 1; /* player starts at level one */
+ c[SPELLMAX] = c[SPELLS] = 1; /* total # spells starts off as 3 */
+ c[REGENCOUNTER] = 16;
+ c[ECOUNTER] = 96; /* start regeneration correctly */
+ c[SHIELD] = c[WEAR] = c[WIELD] = -1;
+ for (i = 0; i < 26; i++)
+ iven[i] = 0;
+ spelknow[0] = spelknow[1] = 1; /* he knows protection, magic missile */
+ if (c[HARDGAME] <= 0) {
+ iven[0] = OLEATHER;
+ iven[1] = ODAGGER;
+ ivenarg[1] = ivenarg[0] = c[WEAR] = 0;
+ c[WIELD] = 1;
+ }
+ playerx = rnd(MAXX - 2);
+ playery = rnd(MAXY - 2);
+ oldx = 0;
+ oldy = 25;
+ gltime = 0; /* time clock starts at zero */
+ cbak[SPELLS] = -50;
+ for (i = 0; i < 6; i++)
+ c[i] = 12; /* make the attributes, ie str, int, etc. */
+ recalc();
+}
+
+
+/*
+ newcavelevel(level)
+ int level;
+
+ function to enter a new level. This routine must be called anytime the
+ player changes levels. If that level is unknown it will be created.
+ A new set of monsters will be created for a new level, and existing
+ levels will get a few more monsters.
+ Note that it is here we remove genocided monsters from the present level.
+ */
+void
+newcavelevel(int x)
+{
+ int i, j;
+ if (beenhere[level])
+ savelevel(); /* put the level back into storage */
+ level = x; /* get the new level and put in working
+ * storage */
+ if (beenhere[x]) {
+ getlevel();
+ sethp(0);
+ checkgen();
+ return;
+ }
+
+ /* fill in new level */
+ for (i = 0; i < MAXY; i++)
+ for (j = 0; j < MAXX; j++)
+ know[j][i] = mitem[j][i] = 0;
+ makemaze(x);
+ makeobject(x);
+ beenhere[x] = 1;
+ sethp(1);
+ checkgen(); /* wipe out any genocided monsters */
+
+#if WIZID
+ if (wizard || x == 0)
+#else
+ if (x == 0)
+#endif
+ for (j = 0; j < MAXY; j++)
+ for (i = 0; i < MAXX; i++)
+ know[i][j] = 1;
+}
+
+/*
+ makemaze(level)
+ int level;
+
+ subroutine to make the caverns for a given level. only walls are made.
+ */
+static int mx, mxl, mxh, my, myl, myh, tmp2;
+
+static void
+makemaze(int k)
+{
+ int i, j, tmp;
+ int z;
+ if (k > 1 && (rnd(17) <= 4 || k == MAXLEVEL - 1 || k == MAXLEVEL + MAXVLEVEL - 1)) {
+ if (cannedlevel(k))
+ return; /* read maze from data file */
+ }
+ if (k == 0)
+ tmp = 0;
+ else
+ tmp = OWALL;
+ for (i = 0; i < MAXY; i++)
+ for (j = 0; j < MAXX; j++)
+ item[j][i] = tmp;
+ if (k == 0)
+ return;
+ eat(1, 1);
+ if (k == 1)
+ item[33][MAXY - 1] = 0; /* exit from dungeon */
+
+ /* now for open spaces -- not on level 10 */
+ if (k != MAXLEVEL - 1) {
+ tmp2 = rnd(3) + 3;
+ for (tmp = 0; tmp < tmp2; tmp++) {
+ my = rnd(11) + 2;
+ myl = my - rnd(2);
+ myh = my + rnd(2);
+ if (k < MAXLEVEL) {
+ mx = rnd(44) + 5;
+ mxl = mx - rnd(4);
+ mxh = mx + rnd(12) + 3;
+ z = 0;
+ } else {
+ mx = rnd(60) + 3;
+ mxl = mx - rnd(2);
+ mxh = mx + rnd(2);
+ z = makemonst(k);
+ }
+ for (i = mxl; i < mxh; i++)
+ for (j = myl; j < myh; j++) {
+ item[i][j] = 0;
+ if ((mitem[i][j] = z))
+ hitp[i][j] = monster[z].hitpoints;
+ }
+ }
+ }
+ if (k != MAXLEVEL - 1) {
+ my = rnd(MAXY - 2);
+ for (i = 1; i < MAXX - 1; i++)
+ item[i][my] = 0;
+ }
+ if (k > 1)
+ treasureroom(k);
+}
+
+/*
+ function to eat away a filled in maze
+ */
+void
+eat(int xx, int yy)
+{
+ int dir, try;
+ dir = rnd(4);
+ try = 2;
+ while (try) {
+ switch (dir) {
+ case 1:
+ if (xx <= 2)
+ break; /* west */
+ if ((item[xx - 1][yy] != OWALL) || (item[xx - 2][yy] != OWALL))
+ break;
+ item[xx - 1][yy] = item[xx - 2][yy] = 0;
+ eat(xx - 2, yy);
+ break;
+
+ case 2:
+ if (xx >= MAXX - 3)
+ break; /* east */
+ if ((item[xx + 1][yy] != OWALL) || (item[xx + 2][yy] != OWALL))
+ break;
+ item[xx + 1][yy] = item[xx + 2][yy] = 0;
+ eat(xx + 2, yy);
+ break;
+
+ case 3:
+ if (yy <= 2)
+ break; /* south */
+ if ((item[xx][yy - 1] != OWALL) || (item[xx][yy - 2] != OWALL))
+ break;
+ item[xx][yy - 1] = item[xx][yy - 2] = 0;
+ eat(xx, yy - 2);
+ break;
+
+ case 4:
+ if (yy >= MAXY - 3)
+ break; /* north */
+ if ((item[xx][yy + 1] != OWALL) || (item[xx][yy + 2] != OWALL))
+ break;
+ item[xx][yy + 1] = item[xx][yy + 2] = 0;
+ eat(xx, yy + 2);
+ break;
+ };
+ if (++dir > 4) {
+ dir = 1;
+ --try;
+ }
+ }
+}
+
+/*
+ * function to read in a maze from a data file
+ *
+ * Format of maze data file: 1st character = # of mazes in file (ascii digit)
+ * For each maze: 18 lines (1st 17 used) 67 characters per line
+ *
+ * Special characters in maze data file:
+ *
+ * # wall D door . random monster
+ * ~ eye of larn ! cure dianthroritis
+ * - random object
+ */
+static int
+cannedlevel(int k)
+{
+ char *row;
+ int i, j;
+ int it, arg, mit, marg;
+ if (lopen(larnlevels) < 0) {
+ write(1, "Can't open the maze data file\n", 30);
+ died(-282);
+ return (0);
+ }
+ i = lgetc();
+ if (i <= '0') {
+ died(-282);
+ return (0);
+ }
+ for (i = 18 * rund(i - '0'); i > 0; i--)
+ lgetl(); /* advance to desired maze */
+ for (i = 0; i < MAXY; i++) {
+ row = lgetl();
+ for (j = 0; j < MAXX; j++) {
+ it = mit = arg = marg = 0;
+ switch (*row++) {
+ case '#':
+ it = OWALL;
+ break;
+ case 'D':
+ it = OCLOSEDDOOR;
+ arg = rnd(30);
+ break;
+ case '~':
+ if (k != MAXLEVEL - 1)
+ break;
+ it = OLARNEYE;
+ mit = rund(8) + DEMONLORD;
+ marg = monster[mit].hitpoints;
+ break;
+ case '!':
+ if (k != MAXLEVEL + MAXVLEVEL - 1)
+ break;
+ it = OPOTION;
+ arg = 21;
+ mit = DEMONLORD + 7;
+ marg = monster[mit].hitpoints;
+ break;
+ case '.':
+ if (k < MAXLEVEL)
+ break;
+ mit = makemonst(k + 1);
+ marg = monster[mit].hitpoints;
+ break;
+ case '-':
+ it = newobject(k + 1, &arg);
+ break;
+ };
+ item[j][i] = it;
+ iarg[j][i] = arg;
+ mitem[j][i] = mit;
+ hitp[j][i] = marg;
+
+#if WIZID
+ know[j][i] = (wizard) ? 1 : 0;
+#else
+ know[j][i] = 0;
+#endif
+ }
+ }
+ lrclose();
+ return (1);
+}
+
+/*
+ function to make a treasure room on a level
+ level 10's treasure room has the eye in it and demon lords
+ level V3 has potion of cure dianthroritis and demon prince
+ */
+static void
+treasureroom(int lv)
+{
+ int tx, ty, xsize, ysize;
+
+ for (tx = 1 + rnd(10); tx < MAXX - 10; tx += 10)
+ if ((lv == MAXLEVEL - 1) || (lv == MAXLEVEL + MAXVLEVEL - 1) || rnd(13) == 2) {
+ xsize = rnd(6) + 3;
+ ysize = rnd(3) + 3;
+ ty = rnd(MAXY - 9) + 1; /* upper left corner of room */
+ if (lv == MAXLEVEL - 1 || lv == MAXLEVEL + MAXVLEVEL - 1)
+ troom(lv, xsize, ysize, tx = tx + rnd(MAXX - 24), ty, rnd(3) + 6);
+ else
+ troom(lv, xsize, ysize, tx, ty, rnd(9));
+ }
+}
+
+/*
+ * subroutine to create a treasure room of any size at a given location
+ * room is filled with objects and monsters
+ * the coordinate given is that of the upper left corner of the room
+ */
+static void
+troom(int lv, int xsize, int ysize, int tx, int ty, int glyph)
+{
+ int i, j;
+ int tp1, tp2;
+ for (j = ty - 1; j <= ty + ysize; j++)
+ for (i = tx - 1; i <= tx + xsize; i++) /* clear out space for
+ * room */
+ item[i][j] = 0;
+ for (j = ty; j < ty + ysize; j++)
+ for (i = tx; i < tx + xsize; i++) { /* now put in the walls */
+ item[i][j] = OWALL;
+ mitem[i][j] = 0;
+ }
+ for (j = ty + 1; j < ty + ysize - 1; j++)
+ for (i = tx + 1; i < tx + xsize - 1; i++) /* now clear out
+ * interior */
+ item[i][j] = 0;
+
+ switch (rnd(2)) { /* locate the door on the treasure room */
+ case 1:
+ item[i = tx + rund(xsize)][j = ty + (ysize - 1) * rund(2)] = OCLOSEDDOOR;
+ iarg[i][j] = glyph; /* on horizontal walls */
+ break;
+ case 2:
+ item[i = tx + (xsize - 1) * rund(2)][j = ty + rund(ysize)] = OCLOSEDDOOR;
+ iarg[i][j] = glyph; /* on vertical walls */
+ break;
+ };
+
+ tp1 = playerx;
+ tp2 = playery;
+ playery = ty + (ysize >> 1);
+ if (c[HARDGAME] < 2)
+ for (playerx = tx + 1; playerx <= tx + xsize - 2; playerx += 2)
+ for (i = 0, j = rnd(6); i <= j; i++) {
+ something(lv + 2);
+ createmonster(makemonst(lv + 1));
+ }
+ else
+ for (playerx = tx + 1; playerx <= tx + xsize - 2; playerx += 2)
+ for (i = 0, j = rnd(4); i <= j; i++) {
+ something(lv + 2);
+ createmonster(makemonst(lv + 3));
+ }
+
+ playerx = tp1;
+ playery = tp2;
+}
+
+
+/*
+ ***********
+ MAKE_OBJECT
+ ***********
+ subroutine to create the objects in the maze for the given level
+ */
+static void
+makeobject(int j)
+{
+ int i;
+ if (j == 0) {
+ fillroom(OENTRANCE, 0); /* entrance to dungeon */
+ fillroom(ODNDSTORE, 0); /* the DND STORE */
+ fillroom(OSCHOOL, 0); /* college of Larn */
+ fillroom(OBANK, 0); /* 1st national bank of larn */
+ fillroom(OVOLDOWN, 0); /* volcano shaft to temple */
+ fillroom(OHOME, 0); /* the players home & family */
+ fillroom(OTRADEPOST, 0); /* the trading post */
+ fillroom(OLRS, 0); /* the larn revenue service */
+ return;
+ }
+ if (j == MAXLEVEL)
+ fillroom(OVOLUP, 0); /* volcano shaft up from the temple */
+
+ /* make the fixed objects in the maze STAIRS */
+ if ((j > 0) && (j != MAXLEVEL - 1) && (j != MAXLEVEL + MAXVLEVEL - 1))
+ fillroom(OSTAIRSDOWN, 0);
+ if ((j > 1) && (j != MAXLEVEL))
+ fillroom(OSTAIRSUP, 0);
+
+ /* make the random objects in the maze */
+
+ fillmroom(rund(3), OBOOK, j);
+ fillmroom(rund(3), OALTAR, 0);
+ fillmroom(rund(3), OSTATUE, 0);
+ fillmroom(rund(3), OPIT, 0);
+ fillmroom(rund(3), OFOUNTAIN, 0);
+ fillmroom(rnd(3) - 2, OIVTELETRAP, 0);
+ fillmroom(rund(2), OTHRONE, 0);
+ fillmroom(rund(2), OMIRROR, 0);
+ fillmroom(rund(2), OTRAPARROWIV, 0);
+ fillmroom(rnd(3) - 2, OIVDARTRAP, 0);
+ fillmroom(rund(3), OCOOKIE, 0);
+ if (j == 1)
+ fillmroom(1, OCHEST, j);
+ else
+ fillmroom(rund(2), OCHEST, j);
+ if ((j != MAXLEVEL - 1) && (j != MAXLEVEL + MAXVLEVEL - 1))
+ fillmroom(rund(2), OIVTRAPDOOR, 0);
+ if (j <= 10) {
+ fillmroom((rund(2)), ODIAMOND, rnd(10 * j + 1) + 10);
+ fillmroom(rund(2), ORUBY, rnd(6 * j + 1) + 6);
+ fillmroom(rund(2), OEMERALD, rnd(4 * j + 1) + 4);
+ fillmroom(rund(2), OSAPPHIRE, rnd(3 * j + 1) + 2);
+ }
+ for (i = 0; i < rnd(4) + 3; i++)
+ fillroom(OPOTION, newpotion()); /* make a POTION */
+ for (i = 0; i < rnd(5) + 3; i++)
+ fillroom(OSCROLL, newscroll()); /* make a SCROLL */
+ for (i = 0; i < rnd(12) + 11; i++)
+ fillroom(OGOLDPILE, 12 * rnd(j + 1) + (j << 3) + 10); /* make GOLD */
+ if (j == 5)
+ fillroom(OBANK2, 0); /* branch office of the bank */
+ froom(2, ORING, 0); /* a ring mail */
+ froom(1, OSTUDLEATHER, 0); /* a studded leather */
+ froom(3, OSPLINT, 0); /* a splint mail */
+ froom(5, OSHIELD, rund(3)); /* a shield */
+ froom(2, OBATTLEAXE, rund(3)); /* a battle axe */
+ froom(5, OLONGSWORD, rund(3)); /* a long sword */
+ froom(5, OFLAIL, rund(3)); /* a flail */
+ froom(4, OREGENRING, rund(3)); /* ring of regeneration */
+ froom(1, OPROTRING, rund(3)); /* ring of protection */
+ froom(2, OSTRRING, 4); /* ring of strength + 4 */
+ froom(7, OSPEAR, rnd(5)); /* a spear */
+ froom(3, OORBOFDRAGON, 0); /* orb of dragon slaying */
+ froom(4, OSPIRITSCARAB, 0); /* scarab of negate spirit */
+ froom(4, OCUBEofUNDEAD, 0); /* cube of undead control */
+ froom(2, ORINGOFEXTRA, 0); /* ring of extra regen */
+ froom(3, ONOTHEFT, 0); /* device of antitheft */
+ froom(2, OSWORDofSLASHING, 0); /* sword of slashing */
+ if (c[BESSMANN] == 0) {
+ froom(4, OHAMMER, 0); /* Bessman's flailing hammer */
+ c[BESSMANN] = 1;
+ }
+ if (c[HARDGAME] < 3 || (rnd(4) == 3)) {
+ if (j > 3) {
+ froom(3, OSWORD, 3); /* sunsword + 3 */
+ froom(5, O2SWORD, rnd(4)); /* a two handed sword */
+ froom(3, OBELT, 4); /* belt of striking */
+ froom(3, OENERGYRING, 3); /* energy ring */
+ froom(4, OPLATE, 5); /* platemail + 5 */
+ }
+ }
+}
+
+/*
+ subroutine to fill in a number of objects of the same kind
+ */
+
+static void
+fillmroom(int n, int what_i, int arg)
+{
+ int i;
+ char what;
+
+ /* truncate to char width (just in case it matters) */
+ what = (char)what_i;
+ for (i = 0; i < n; i++)
+ fillroom(what, arg);
+}
+
+static void
+froom(int n, int theitem, int arg)
+{
+ if (rnd(151) < n)
+ fillroom(theitem, arg);
+}
+
+/*
+ subroutine to put an object into an empty room
+ * uses a random walk
+ */
+static void
+fillroom(int what_i, int arg)
+{
+ int x, y;
+ char what;
+
+ /* truncate to char width (just in case it matters) */
+ what = (char)what_i;
+
+#ifdef EXTRA
+ c[FILLROOM]++;
+#endif
+
+ x = rnd(MAXX - 2);
+ y = rnd(MAXY - 2);
+ while (item[x][y]) {
+
+#ifdef EXTRA
+ c[RANDOMWALK]++;/* count up these random walks */
+#endif
+
+ x += rnd(3) - 2;
+ y += rnd(3) - 2;
+ if (x > MAXX - 2)
+ x = 1;
+ if (x < 1)
+ x = MAXX - 2;
+ if (y > MAXY - 2)
+ y = 1;
+ if (y < 1)
+ y = MAXY - 2;
+ }
+ item[x][y] = what;
+ iarg[x][y] = arg;
+}
+
+/*
+ subroutine to put monsters into an empty room without walls or other
+ monsters
+ */
+int
+fillmonst(int what)
+{
+ int x, y, trys;
+ for (trys = 5; trys > 0; --trys) { /* max # of creation attempts */
+ x = rnd(MAXX - 2);
+ y = rnd(MAXY - 2);
+ if ((item[x][y] == 0) && (mitem[x][y] == 0) && ((playerx != x) || (playery != y))) {
+ mitem[x][y] = what;
+ know[x][y] = 0;
+ hitp[x][y] = monster[what].hitpoints;
+ return (0);
+ }
+ }
+ return (-1); /* creation failure */
+}
+
+/*
+ creates an entire set of monsters for a level
+ must be done when entering a new level
+ if sethp(1) then wipe out old monsters else leave them there
+ */
+static void
+sethp(int flg)
+{
+ int i, j;
+ if (flg)
+ for (i = 0; i < MAXY; i++)
+ for (j = 0; j < MAXX; j++)
+ stealth[j][i] = 0;
+ if (level == 0) {
+ c[TELEFLAG] = 0;
+ return;
+ } /* if teleported and found level 1 then know
+ * level we are on */
+ if (flg)
+ j = rnd(12) + 2 + (level >> 1);
+ else
+ j = (level >> 1) + 1;
+ for (i = 0; i < j; i++)
+ fillmonst(makemonst(level));
+ positionplayer();
+}
+
+/*
+ * Function to destroy all genocided monsters on the present level
+ */
+static void
+checkgen(void)
+{
+ int x, y;
+ for (y = 0; y < MAXY; y++)
+ for (x = 0; x < MAXX; x++)
+ if (monster[mitem[x][y]].genocided)
+ mitem[x][y] = 0; /* no more monster */
+}