root/games/warp/init.c
/* Header: init.c,v 7.0.1.4 86/12/12 16:58:03 lwall Exp */

/* Log: init.c,v
 * Revision 7.0.1.4  86/12/12  16:58:03  lwall
 * Baseline for net release.
 *
 * Revision 7.0.1.3  86/10/20  14:35:31  lwall
 * Picked some lint.
 *
 * Revision 7.0.1.2  86/10/17  15:53:30  lwall
 * Added random walk star fields.
 *
 * Revision 7.0.1.1  86/10/16  10:51:19  lwall
 * Added Damage.  Fixed random bugs.
 *
 * Revision 7.0  86/10/08  15:12:10  lwall
 * Split into separate files.  Added amoebas and pirates.
 *
 */

#include "EXTERN.h"
#include "warp.h"
#include "bang.h"
#include "object.h"
#include "move.h"
#include "play.h"
#include "score.h"
#include "term.h"
#include "them.h"
#include "us.h"
#include "util.h"
#include "weapon.h"
#include "INTERN.h"
#include "init.h"

void
initialize(void)
{
    int i;
    int x;
    int y;
    int dist;
    int ydist = 0;
    int xdist = 0;
    long e;
    int yoff = 0, xoff = 0, ypred, xpred;
    OBJECT *obj = NULL;
    char ch;
    FILE *mapfp = NULL;
    bool tmptholspec;
    int inhabjackpot;
    long inhenergy;
    int walksplit = 200;
    static const char *distname[] =
        {" #"," -"," \\"," /",
         " |"," *"," `"," '"};

    cloaking = madgorns = false;
    deados = madfriends = 0;
    curscore = possiblescore = 0L;
    yamblast = xamblast = ambsize = 0;
    if (smarts > 90)
        massacre = true;
    scandist = (massacre?20:15);
    antibase = (smarts>60?1:(smarts>40?2:(smarts>25?4:100)));
    sm35 = (smarts>35?35:smarts);
    sm45 = (smarts>45?45:smarts);
    sm50 = (smarts>50?50:smarts);
    sm55 = (smarts>55?55:smarts);
    sm80 = (smarts>80?80:smarts);
    sm95 = (smarts>95?95:smarts);
    super = (smarts>50?smarts-50:0);
    enemshields = 10 + super/2;         /* (scaled by 10) 1 @ 50 .. 3 @ 90 */
    if (smarts>90)
        enemshields += (smarts-90)*10;  /* lay it on thick: ~13 @ 99 */
    entmax = (smarts>=75?5000:(smarts>=50?4000:(smarts>=40?3000:2000)));
    basemax = (smarts>=75?20000:(smarts>=50?15000:(smarts>=40?12500:10000)));

    clear();
    while (root.next != &root) {
        root.next = root.next->next;
        free_object(root.next->prev);
    }
    root.prev = &root;
    enemies = movers = NULL;
    numos = numxes = 0;
#if defined(vax) && XYSIZEx4 == 3680
    asm("movc5 $0,_occupant,$0,$3680,_occupant");
    asm("movc5 $0,_blast,$0,$3680,_blast");     /* 3680 = XYSIZEx4 */
    asm("movc5 $0,_amb,$32,$920,_amb");
#else
    for (y=0;y<YSIZE;y++)
        for (x=0;x<XSIZE;x++) {
            occupant[y][x] = 0;
            blast[y][x] = 0;
            amb[y][x] = ' ';
        }
#endif
    for (y=0; y<YSIZE; y++)
        yblasted[y] = 0;
    for (x=0; x<XSIZE; x++)
        xblasted[x] = 0;
    blasted = false;
    if (!starspec) {
        if (smarts < 15)
            inumstars = 50 + rand_mod(50);
        else if (smarts < 50 || smarts > 85)
            inumstars = exdis(800) + rand_mod(100) + 1;
        else /* too few stars makes 50..85 too hard */
            inumstars = exdis(700) + rand_mod(150-super*2) + 50+super*2;
    }
    tmptholspec = (smarts > 15 && inumstars < 450 && ! rand_mod(90-sm80));
    if (!klingspec) {
        inumenemies = rand_mod((smarts+1)/2) + 1;
        if (massacre || tmptholspec)
            inumenemies += 10;
    }
    if (!friendspec)
        inumfriends = rand_mod(smarts/8+1);
    if (!piratespec)
        inumpirates = rand_mod(inumfriends/2+1);
    if (inumfriends+inumenemies+inumstars > YSIZE*XSIZE-20)
        inumstars = YSIZE*XSIZE-20 - inumenemies - inumfriends;
    if (inumstars < 0) {
        inumfriends += inumstars;
        inumstars = 0;
    }
    if (inumfriends < 0) {
        inumenemies += inumfriends;
        inumfriends = 0;
    }
    if (inumenemies < 0)
        inumenemies = 0;
    numstars = inumstars;
    inuminhab = numinhab = 0;
    inumroms = inumthols = inumgorns = 0;
    numapollos = apolspec || massacre ? 1 :
       ((!numstars || rand_mod(2) || smarts < 10) ? 0 : 1);
    inumapollos = apolloflag = 0;
    realapollo = NULL;
    inumcrushes = numcrushes =
        crushspec||massacre?1:(rand_mod(2000) < inumstars);
    inumenemies += inumcrushes;
    inumamoebas = numamoebas = (amoebaspec ? 1 :
        !rand_mod(inumcrushes?3-massacre:8) );  /* < and & are fun together */
    inumenemies += inumamoebas;
    if (!rand_mod(40)) {
        inhabjackpot = 32767;
        inumfriends += rand_mod(10);
        inumpirates += rand_mod(10);
    }
    else
        inhabjackpot = inumpirates;
    inhenergy = 30000-super*150;
    if (!rand_mod(10))
        inhenergy = 50000;
    if (!rand_mod(4))
        inhenergy += rand_mod(3500+super*150);
    numfriends = inumfriends;
    numpirates = inumpirates;
    numenemies = inumenemies;
    deadmudds = 0;

    /* do stars */

stars_again:
    if (prespec)
        dist = 4;
    else if (numstars > 750)
        dist = 0;
    else
        dist = rand_mod(starspec||smarts<=5?3:5);
    if (debugging) {
        real_y = real_x = -100;
        printf("\r\n");
    }
    switch (dist) {
    case 0:                             /* uniform random */
        ydist = xdist = 0;
        if (inumstars < 700 && !rand_mod(3-(inumstars<50))) {
            ydist = xdist = 6;          /* well, maybe not so random */
            y = rand_mod(YSIZE);
            x = rand_mod(XSIZE);
            if (rand_mod(2))
                walksplit = inumstars/(exdis(40)+1);
        }
        if (debugging)
            printf(" R\r\n");
        break;
    case 1: case 2:     /* clumped, maybe skewed, maybe superposed */
        ydist = rand_mod(4);
        xdist = rand_mod(2);
        if (debugging)
            printf("%s\r\n",distname[ydist+4*xdist]);
        yoff = rand_mod(YSIZE);
        xoff = rand_mod(XSIZE);
        if (dist == 2)
            dist = numstars/2 + exdis(numstars/2) - exdis(numstars/2);
        else
            dist = 0;
        break;
    case 3: case 4:                     /* predefined or residual */
      scenario_again:
        if (debugging)
            printf(" P\r\n");
        dist = 0;
        snprintf(spbuf, sizeof(spbuf), "smap.%d",
            (prescene>=0?prescene:rand_mod(MAPS)) );
        if ((mapfp = fopen(spbuf,"r")) != NULL &&
            fgets(spbuf,10,mapfp) != NULL ) {
            inumstars = numstars = atoi(spbuf);
            if (inumenemies+inumstars > YSIZE*XSIZE-20)
                inumstars = numstars = YSIZE*XSIZE-20 - inumenemies;
            ydist = rand_mod(2) + 4;    /* flip y axis? */
            xdist = rand_mod(2) + 4;    /* flip x axis? */
            yoff = rand_mod(YSIZE);     /* how much to shift y */
            xoff = rand_mod(XSIZE);     /* how much to shift x */
        }
        else {
            prespec = false;
            prescene = -1;
            if (rand_mod(2))
                goto scenario_again;
            goto stars_again;
        }
        break;
    }
    for (i = 1; i <= numstars; i++) {
        if (dist && i == dist) {        /* flip to another skewing? */
            ydist = rand_mod(4);
            xdist = rand_mod(2);
            if (!rand_mod(4)) {
                ydist = xdist = 6;
                if (debugging)
                    printf("&\r\n");
            }
            else if (debugging)
                printf("%s\r\n",distname[ydist+4*xdist]);
            yoff = rand_mod(YSIZE);
            xoff = rand_mod(XSIZE);
            dist = 0;
        }
        do {                            /* until an open spot found */
            switch (xdist) {
            case 0:
                x = rand_mod(XSIZE);    /* pick from 0..39, uniform */
                break;
            case 1: case 2: case 3:
                x = (int)((((double)(myrand()-HALFRAND)) *
                           ((double)(myrand()-HALFRAND))/RANDRAND)
                          * 20.0) + xoff;       /* pick from -20..20, clumped */
                break;
            case 4:
                if (fscanf(mapfp,"%d %d\n",&ypred,&xpred) == EOF)
                    ydist = xdist = 0;
                x = xpred + xoff;
                break;
            case 5:
                if (fscanf(mapfp,"%d %d\n",&ypred,&xpred) == EOF)
                    ydist = xdist = 0;
                x = -xpred + xoff;
                break;
            case 6:
                x += rand_mod(3) - 1;
                break;
            }
            switch (ydist) {
            case 0:
                y = rand_mod(YSIZE);
                break;
            case 1:
                y = (int)((((double)(myrand()-HALFRAND)) *
                           ((double)(myrand()-HALFRAND))/RANDRAND)
                          * 12.0) + yoff;       /* pick from -12..12, clumped */
                break;
            case 2:
#ifndef lint
                y = (int)((((double)(myrand()-HALFRAND)) *
                           ((double)(myrand()-HALFRAND))/RANDRAND)
                          * 12.0) + yoff + x*YSIZE/XSIZE;
                                                /* clumped & skewed */
#endif
                break;
            case 3:
#ifndef lint
                y = (int)((((double)(myrand()-HALFRAND)) *
                           ((double)(myrand()-HALFRAND))/RANDRAND)
                          * 12.0) + yoff - x*YSIZE/XSIZE;
                                                /* clumped & skewed */
#endif
                break;
            case 4:
                y = ypred + yoff;
                break;
            case 5:
                y = -ypred + yoff;
                break;
            case 6:
                y += rand_mod(3) - 1;
#ifdef lint
                walksplit = walksplit;
#endif
                if (!rand_mod(walksplit)) {
                    y = rand_mod(YSIZE);
                    x = rand_mod(XSIZE);
                }
                break;
            }
            while (x<0) x += XSIZE00;
            while (y<0) y += YSIZE00;
            x %= XSIZE;
            y %= YSIZE;
        } while (occupant[y][x]);
        e = rand_mod(32768);
        if (--inhabjackpot > 0 || e >= inhenergy) {
            ch = '@';
            if (inhabjackpot && e < 10000)
                e += 10000;
            inuminhab = ++numinhab;
        }
        else {
            ch = '*';
        }
        obj = make_object(Star,ch,y,x,0,0,e+rand_mod(super*100+1),e/4,&root);
        obj->flags |= STATIC;
    }
    if (inumstars > 30 && inhabjackpot <= 0 &&
         !rand_mod(3 - (inumstars > 400) - (inhenergy > 32768)) ) {
        int initx;
        int inity;

        x = initx = obj->posx;
        y = inity = obj->posy;
        while (rand_mod(2) && inuminhab < inumstars/2) {
            for (i=rand_mod(smarts)*2+20; i; i--) {
                if ((obj = occupant[y][x]) && obj->image == '*') {
                    setimage(obj,'@');
                    if (obj->energy < 10000)
                        obj->energy += 20000; /* the benefits of civilization */
                    inuminhab = ++numinhab;
                }
                if (i&15) {
                    y = (y + rand_mod(3) + YSIZE99) % YSIZE;
                    x = (x + rand_mod(3) + XSIZE99) % XSIZE;
                }
                else {                  /* don't wander too far */
                    y = inity;
                    x = initx;
                }
            }
            x = initx = rand_mod(XSIZE);
            y = inity = rand_mod(YSIZE);
        }
    }
    if (mapfp != NULL)
        fclose(mapfp);
    if (numcrushes) {
        do {
            x = rand_mod(XSIZE);
            y = rand_mod(YSIZE);
        } while (occupant[y][x]);
        movers = make_object(Crusher,'<',y,x,0,1,32767L,32768L,&root);
        possiblescore += 10000;
    }
    ient = (numents != 0);
    if (ient) {
        do {
            x = rand_mod(XSIZE);
            y = rand_mod(YSIZE);
        } while (occupant[y][x]);
        e = entmax;
        ent = make_object(Enterprise,'E',y,x,0,0,e,e/2,&root);
        if (!movers)
            movers = ent;
    }
    ibase = (numbases != 0);
    if (ibase) {
        e = 52-super;
        do {
            x = rand_mod(XSIZE);
            y = rand_mod(YSIZE);
        } while (occupant[y][x] || lookaround(y,x,Star) * 7 < e--);
        e = basemax;
        base = make_object(Base, 'B',y,x,0,0,e,e/4,&root);
        if (!movers)
            movers = base;
    }
    if (numamoebas) {
        do {
            x = rand_mod(XSIZE);
            y = rand_mod(YSIZE);
        } while (occupant[y][x]);
        nuke = make_object(Enemy,'&',y,x,0,0,32767L,
          (long)entmax+entmax+rand_mod(entmax),&root);
        possiblescore += 10000;
        amb[y][x] = '~';
        if (rand_mod(2))
            modify_amoeba(y,x,2,'~',(int)rand_mod(smarts<<1));/* just make blob */
        else {
            for (i=smarts/10+1; i; i--) {
                nuke->strategy = rand_mod(256);         /* random direction */
                modify_amoeba(y,x,2,'~',(int)rand_mod(5));
                modify_amoeba(y,x,2,'~',(int)rand_mod(5));
                modify_amoeba(y,x,2,'~',(int)rand_mod(5));
                modify_amoeba(y,x,2,'~',(int)rand_mod(5));      /* extend pseudopod */
            }
        }
        if (!enemies)
            enemies = nuke;
        if (!movers)
            movers = nuke;
    }
    if (rand_mod(27-sm50/2) && !romspec && !gornspec)
        dist = 27-sm50/2;
    else
        dist = rand_mod(4) + 1;
    for (i = 1+inumcrushes+inumamoebas; i <= numenemies; i++) {
        do {
            x = rand_mod(XSIZE);
            y = rand_mod(YSIZE);
        } while (occupant[y][x]);
        if (rand_mod(dist)) {
            if (!tholspec && !tmptholspec && rand_mod((inumstars*3)/sm50+2))
                ch = 'K';
            else {
                ch = 'T';
                inumthols++;
            }
        }
        else {
            if (romspec == gornspec)
                e = 50;
            else if (gornspec)
                e = 10;
            else
                e = 90;
            if (rand_mod(100) < e) {
                ch = 'R';
                inumroms++;
            }
            else {
                ch = 'G';
                inumgorns++;
            }
        }
        if (possiblescore > ENTBOUNDARY - 10000)
            e = (ENTBOUNDARY - possiblescore) / 5;
        else
            e = 250 + (sm50-1) * 30 * 20 / numenemies+1;
#ifndef lint
        e = exdis((int)e) + e - exdis((int)e);
        obj = make_object(Enemy,ch,y,x,0,0,
            e + rand_mod(super*200+2) + 10000*massacre,e/4,&root);
#endif
        e /= 4;
        switch (ch) {
        case 'K':
            possiblescore += e;
            break;
        case 'T':
            possiblescore += e*3/2;
            break;
        case 'G':
            possiblescore += e*2;
            break;
        case 'R':
            possiblescore += e*3;
            obj->flags |= CLOAKS;
            break;
        }
        if (!enemies)
            enemies = obj;
        if (!movers)
            movers = obj;
    }
    numgorns = inumgorns;
    for (i=0; i<numfriends; i++) {
        do {
            x = rand_mod(XSIZE);
            y = rand_mod(YSIZE);
        } while (occupant[y][x]);
        e = 250 + (sm50-1) * 30 * 20 / numenemies+1;
#ifndef lint
        e = exdis((int)e) + e - exdis((int)e);
#endif
        {
            static char let[] = "QWYUISDHJLZVMFFFFFFFFF";

            dist = rand_mod(20);
            ch = let[dist];
        }               /* grr, venix doesn't like strchring into string */
        obj = make_object(Enemy,ch,y,x,0,0,
            e + rand_mod(super*200+2),e/4,&root);
        if (numpirates-- > 0) {
            obj->flags |= PIRATE;
            if (smarts >= 20 && !rand_mod(10-smarts/10))
                obj->flags |= CLOAKS;
        }
        obj->flags |= FRIENDLY;
        if (!enemies)
            enemies = obj;
        if (!movers)
            movers = obj;
    }
    if (!movers)
        movers = &root;
    if (!enemies)
        enemies = &root;
    if (ent)
        mvaddch(ent->posy+1, ent->posx*2, ent->image);
    if (base)
        mvaddch(base->posy+1, base->posx*2, base->image);
    sleep(2);
    {
        OBJECT *curobj;

        for (curobj = root.next; curobj != &root; curobj = curobj->next) {
            mvaddch(curobj->posy+1, curobj->posx*2, curobj->image);
        }
    }

    for (i=0;i<2;i++) for (y=0;y<3;y++) for (x=0;x<3;x++)
    isatorp[i][y][x]=0;

    whenok = 0;
    timer = 0;
    finish = 0;
    bombed_out = false;
    if (ent)
        entmode = status = 0;
    else
        if (base)
            status = 2;
        else
            status = 3;

    snprintf(spbuf, sizeof(spbuf),
    "%-4s E: %4d %2d B: %5d %3d Enemies: %-3d Stars: %-3d Stardate%5d.%1d %9ld",
        "   ", 0, 0, 0, 0, 0, 0, smarts * 100, 0, 0L);
    mvaddstr(0,0,spbuf);
    oldeenergy = oldbenergy = oldcurscore =
    oldstatus = oldetorp = oldbtorp = oldstrs = oldenemies = -1;
                                        /* force everything to fill in */
    damage = olddamage = 0;
    for (i=0; i<MAXDAMAGE; i++)
        damflag[i] = 0;
    btorp = 500;
    etorp = 50;
}