/*
        WHMSC.C
*/

#include "icorp.h"
#include <memcheck.h>

static
int  cursbot,
     curstop,
     cursx,
     cursy,
     winx1,
     winy1,
     winx2,
     winy2,
     winatr;

#if MULTIPLAYER
int  ipxflag;

int  totstarts;

long fakepersec,
     gotlastpacketclock,
     movefifoend,
     movefifoplc,
     ototalclock,
     ready2send;

struct baksync baksync[MAXPLAYERS],
    *baksyncptr[MAXPLAYERS];

struct multistart multistart[MAXMULTISTARTS],
    *multistartptr[MAXMULTISTARTS];

char synckeys[MAXSYNCKEYS] = {
     KEYFWD, KEYBACK, KEYLEFT, KEYRIGHT, KEYRUN, KEYSTRAFE, KEYFIRE, KEYUSE,
     KEYELEVUP, KEYELEVDN, KEYSTAND, KEYLAY, KEYUP, KEYDOWN, KEYGUN1, KEYGUN2,
     KEYGUN3, KEYGUN4, KEYGUN5, KEYGUN6
};

char tempbuf[576];


//   DPMI stuff

struct rmreg {                     // real mode register pack
     unsigned long edi;
     unsigned long esi;
     unsigned long ebp;
     unsigned long rsv;
     unsigned long ebx;
     unsigned long edx;
     unsigned long ecx;
     unsigned long eax;
     unsigned short flags;
     unsigned short es;
     unsigned short ds;
     unsigned short fs;
     unsigned short gs;
     unsigned short ip;
     unsigned short cs;
     unsigned short sp;
     unsigned short ss;
}    rmreg;

struct ipxentry {
     unsigned short cs;
     unsigned short ip;
}    ipxentry;
#endif


void
faketimerhandler(void)
{
#if MULTIPLAYER
     short other,
          tempbufleng;
     long i,
          j,
          k,
          l;
     struct player *plr;
     struct playerext *plrx;

     if (totalclock < ototalclock + TICSPERFRAME) {
          return;
     }
     if (ready2send == 0) {
          return;
     }
     fakepersec++;
     ototalclock = totalclock;
     if ((pyrn == connecthead) || (option[4] == 0)) {
          if (option[4] != 0) {
               while ((tempbufleng = getpacket(&other, tempbuf)) > 0) {
                    plr = plptrlist[other];
                    plrx = (struct playerext *) plr->ext1;
                    switch (tempbuf[0]) {
                    case 1:        // [1] (receive slave sync buffer)
                         j = 2;
                         k = tempbuf[1];
                         if (k & 1) {
                              plrx->vel = tempbuf[j++];
                         }
                         if (k & 2) {
                              plrx->svel = tempbuf[j++];
                         }
                         if (k & 4) {
                              plrx->angvel = tempbuf[j++];
                         }
                         if (k & 8) {
                              plrx->syncbits = ((plrx->syncbits & 0xFFFFFF00) | ((long) tempbuf[j++]));
                         }
                         if (k & 16) {
                              plrx->syncbits = ((plrx->syncbits & 0xFFFF00FF) | ((long) tempbuf[j++] << 8));
                         }
                         if (k & 32) {
                              plrx->syncbits = ((plrx->syncbits & 0xFF00FFFF) | ((long) tempbuf[j++] << 16));
                         }
                         if (k & 64) {
                              plrx->syncbits = ((plrx->syncbits & 0x00FFFFFF) | ((long) tempbuf[j++] << 24));
                         }
                         if (k & 128) {
                              plrx->weapon = tempbuf[j++];
                         }
                         break;
                    case 2:        // typed message text
                         break;
                    case 3:        // voice transmission
                         break;
                    case 255:      // [255] (logout)
                         showmessage("Player %d left the game", other);
                         deletesprite(plr->spritenum);
                         break;
                    }
               }
          }
          if (getoutputcirclesize() < 16) {
               getinput(plptrlist[pyrn]);
               if (option[4] != 0) {
                    tempbuf[0] = 0;
                    tempbuf[1] = numplayers;
                    j = 2;
                    for (i = connecthead; i >= 0; i = connectpoint2[i]) {
                         plr = plptrlist[i];
                         plrx = (struct playerext *) plr->ext1;
                         tempbuf[j] = (plr->x & 0x000000FF);
                         tempbuf[j + 1] = (plr->x >> 8) & 0x000000FF;
                         tempbuf[j + 2] = (plr->x >> 16) & 0x000000FF;
                         tempbuf[j + 3] = (plr->x >> 24) & 0x000000FF;
                         j += 4;
                         tempbuf[j] = (plr->y & 0x000000FF);
                         tempbuf[j + 1] = (plr->y >> 8) & 0x000000FF;
                         tempbuf[j + 2] = (plr->y >> 16) & 0x000000FF;
                         tempbuf[j + 3] = (plr->y >> 24) & 0x000000FF;
                         j += 4;
                         tempbuf[j] = (plr->z & 0x000000FF);
                         tempbuf[j + 1] = (plr->z >> 8) & 0x000000FF;
                         tempbuf[j + 2] = (plr->z >> 16) & 0x000000FF;
                         tempbuf[j + 3] = (plr->z >> 24) & 0x000000FF;
                         j += 4;
                         tempbuf[j] = (plr->ang & 0x000000FF);
                         tempbuf[j + 1] = (plr->ang >> 8) & 0x000000FF;
                         j += 2;
                         tempbuf[j] = (plr->sector & 0x000000FF);
                         tempbuf[j + 1] = (plr->sector >> 8) & 0x000000FF;
                         j += 2;
                         tempbuf[j] = (plrx->syncbits & 0xFF);
                         tempbuf[j + 1] = (plrx->syncbits >> 8) & 0xFF;
                         tempbuf[j + 2] = (plrx->syncbits >> 16) & 0xFF;
                         tempbuf[j + 3] = (plrx->syncbits >> 24) & 0xFF;
                         j += 4;
                         tempbuf[j] = plrx->weapon;
                         j += 1;
                         tempbuf[j] = (plrx->health & 0x00FF);
                         tempbuf[j + 1] = (plrx->health >> 8) & 0x00FF;
                         j += 2;
                         plrx->oldvel = plrx->vel;
                         plrx->oldsvel = plrx->svel;
                         plrx->oldangvel = plrx->angvel;
                         plrx->oldsyncbits = plrx->syncbits;
                         if (plrx->weapon != plrx->oldweapon) {
                              memmove(&plrx->weapontype, wptptr[plrx->weapon],
                                      sizeof(struct weapontype));
                              plrx->oldweapon = plrx->weapon;
                         }
                    }
                    for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i]) {
                         sendpacket(i, tempbuf, j);
                    }
               }
               movethings();       // Move EVERYTHING (you too!)
          }
     }
     else {                        // I am a SLAVE
          while ((tempbufleng = getpacket(&other, tempbuf)) > 0) {
               switch (tempbuf[0]) {
               case 0:             // [0] (receive master sync buffer)
                    if (numplayers != tempbuf[1]) {
                         crash("faketimer: numplayers mismatch - "
                               "master=%d,slave=%d", tempbuf[1], numplayers);
                    }
                    j = 2;
                    for (i = connecthead; i >= 0; i = connectpoint2[i]) {
                         plr = plptrlist[i];
                         plrx = (struct playerext *) plr->ext1;
                         plr->x = tempbuf[j] + (tempbuf[j + 1] << 8)
                              + (tempbuf[j + 2] << 16) + (tempbuf[j + 3] << 24);
                         j += 4;
                         plr->y = tempbuf[j] + (tempbuf[j + 1] << 8)
                              + (tempbuf[j + 2] << 16) + (tempbuf[j + 3] << 24);
                         j += 4;
                         plr->z = tempbuf[j] + (tempbuf[j + 1] << 8)
                              + (tempbuf[j + 2] << 16) + (tempbuf[j + 3] << 24);
                         j += 4;
                         plr->ang = tempbuf[j] + (tempbuf[j + 1] << 8);
                         j += 2;
                         plr->sector = tempbuf[j] + (tempbuf[j + 1] << 8);
                         j += 2;
                         plrx->syncbits = tempbuf[j] + (tempbuf[j + 1] << 8)
                              + (tempbuf[j + 2] << 16) + (tempbuf[j + 3] << 24);
                         j += 4;
                         if (i != pyrn) {
                              plrx->weapon = tempbuf[j];
                              if (plrx->weapon != plrx->oldweapon) {
                                   memmove(&plrx->weapontype, wptptr[plrx->weapon],
                                           sizeof(struct weapontype));
                                   plrx->oldweapon = plrx->weapon;
                              }
                         }
                         j += 1;
                         plrx->health = tempbuf[j] + (tempbuf[j + 1] << 8);
                         j += 2;
                    }
                    movethings();  // Move all players and sprites
                    break;
               case 2:
                    break;
               case 3:
                    break;
               case 255:           // [255] (logout)
                    showmessage("Player %d left the game", other);
                    deletesprite(plptrlist[other]->spritenum);
                    break;
               }
          }
          if (getoutputcirclesize() < 16) {
               getinput(plptrlist[pyrn]);
               tempbuf[0] = 1;
               k = 0;
               j = 2;
               plr = plptrlist[pyrn];
               plrx = (struct playerext *) plr->ext1;
               if (plrx->vel != plrx->oldvel) {
                    tempbuf[j++] = plrx->vel;
                    k |= 1;
               }
               if (plrx->svel != plrx->oldsvel) {
                    tempbuf[j++] = plrx->svel;
                    k |= 2;
               }
               if (plrx->angvel != plrx->oldangvel) {
                    tempbuf[j++] = plrx->angvel;
                    k |= 4;
               }
               if ((plrx->syncbits & 0x000000FF) != (plrx->oldsyncbits & 0x000000FF)) {
                    tempbuf[j++] = (plrx->syncbits & 255);
                    k |= 8;
               }
               if ((plrx->syncbits & 0x0000FF00) != (plrx->oldsyncbits & 0x0000FF00)) {
                    tempbuf[j++] = ((plrx->syncbits >> 8) & 255);
                    k |= 16;
               }
               if ((plrx->syncbits & 0x00FF0000) != (plrx->oldsyncbits & 0x00FF0000)) {
                    tempbuf[j++] = ((plrx->syncbits >> 16) & 255);
                    k |= 32;
               }
               if ((plrx->syncbits & 0xFF000000) != (plrx->oldsyncbits & 0xFF000000)) {
                    tempbuf[j++] = ((plrx->syncbits >> 24) & 255);
                    k |= 64;
               }
               if (plrx->weapon != plrx->oldweapon) {
                    tempbuf[j++] = (char) plrx->weapon;
                    k |= 128;
               }
               tempbuf[1] = k;
               plrx->oldvel = plrx->vel;
               plrx->oldsvel = plrx->svel;
               plrx->oldangvel = plrx->angvel;
               plrx->oldsyncbits = plrx->syncbits;
               sendpacket(connecthead, tempbuf, j);
          }
     }
#endif
}


char buf[80];

void
setvmode(int m)
{
     union REGS regs;

     memset(&regs, 0, sizeof(union REGS));
     regs.h.ah = 0x00;
     regs.h.al = m;
     int386(0x10, &regs, &regs);
}

void
setatr(int fore, int back)
{
     winatr = (((back & 0x0F) << 4) | (fore & 0x0F));
}

void
setcsize(int t, int b)
{
     union REGS regs;

     memset(&regs, 0, sizeof(union REGS));
     regs.h.ah = 0x01;
     regs.h.ch = t;
     regs.h.cl = b;
     int386(0x10, &regs, &regs);
}

void
gotoxy(int x, int y)
{
     union REGS regs;

     memset(&regs, 0, sizeof(union REGS));
     regs.h.ah = 0x02;
     regs.h.bh = 0;
     regs.h.dh = y;
     regs.h.dl = x;
     int386(0x10, &regs, &regs);
     cursx = x;
     cursy = y;
}

void
getcurs(void)
{
     union REGS regs;

     memset(&regs, 0, sizeof(union REGS));
     regs.h.ah = 0x03;
     regs.h.bh = 0;
     int386(0x10, &regs, &regs);
     if (curstop == -1) {
          curstop = regs.h.ch;
     }
     if (cursbot == -1) {
          cursbot = regs.h.cl;
     }
     cursy = regs.h.dh;
     cursx = regs.h.dl;
}

void
setregion(int x1, int y1, int x2, int y2)
{
     winx1 = x1;
     winy1 = y1;
     winx2 = x2;
     winy2 = y2;
}

void
scrollup(void)
{
     union REGS regs;

     memset(&regs, 0, sizeof(union REGS));
     regs.h.ah = 0x06;
     regs.h.al = 1;
     regs.h.bh = winatr;
     regs.h.ch = winy1;
     regs.h.cl = winx1;
     regs.h.dh = winy2;
     regs.h.dl = winx2;
     int386(0x10, &regs, &regs);
}

void
scrolldn(void)
{
     union REGS regs;

     memset(&regs, 0, sizeof(union REGS));
     regs.h.ah = 0x07;
     regs.h.al = 1;
     regs.h.bh = winatr;
     regs.h.ch = winy1;
     regs.h.cl = winx1;
     regs.h.dh = winy2;
     regs.h.dl = winx2;
     int386(0x10, &regs, &regs);
}

void
clrregion(int fore, int back)
{
     union REGS regs;

     setatr(fore, back);
     memset(&regs, 0, sizeof(union REGS));
     regs.h.ah = 0x06;
     regs.h.al = 0;
     regs.h.bh = winatr;
     regs.h.ch = winy1;
     regs.h.cl = winx1;
     regs.h.dh = winy2;
     regs.h.dl = winx2;
     int386(0x10, &regs, &regs);
}


void far *
dpmi_getexception(int no)
{
     void far *fp;
     union REGS regs;

     regs.x.eax = 0x202;
     regs.x.ebx = no;
     int386(0x31, &regs, &regs);
     fp = MK_FP(regs.w.cx, regs.x.edx);
     return (fp);
}

void
dpmi_setexception(int no, void far * func)
{
     union REGS regs;

     regs.x.eax = 0x203;
     regs.x.ebx = no;
     regs.x.ecx = FP_SEG(func);
     regs.x.edx = FP_OFF(func);
     int386(0x31, &regs, &regs);
}

#if MULTIPLAYER
int
dpmi_callrealint(int no, struct rmreg * r)
{
     union REGS regs;
     struct SREGS sregs;
     void far *fp;

     fp = (void far *) r;
     segread(&sregs);
     regs.x.eax = 0x300;
     regs.x.ebx = no;
     regs.x.ecx = 0;
     sregs.es = FP_SEG(fp);
     regs.x.edi = FP_OFF(fp);
     r->ss = 0;
     r->sp = 0;
     r->flags = 0;
     int386x(0x31, &regs, &regs, &sregs);
     return (regs.x.cflag);
}

int
isipx(void)
{
     rmreg.eax = 0x7A00;
     dpmi_callrealint(0x2F, &rmreg);
     if ((rmreg.eax & 0x000000FF) != 0xFF) {
          ipxentry.cs = 0;
          ipxentry.ip = 0;
          ipxflag = 0;
     }
     else {
          ipxentry.cs = rmreg.es;
          ipxentry.ip = rmreg.edi & 0xFFFF;
          ipxflag = 1;
     }
     return (ipxflag);
}
#endif
