code:
//-------------------------------------------------------------------------
/*
Copyright (C) 1997, 2005 - 3D Realms Entertainment

This file is part of Shadow Warrior version 1.2

Shadow Warrior is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

Original Source: 1997 - Frank Maddin and Jim Norwood
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------
#include "build.h"

#include "keys.h"
#include "names2.h"
#include "panel.h"
#include "game.h"

//#include "settings.h"
#include "mytypes.h"
#include "scriplib.h"
#include "fx_man.h"
#include "gamedefs.h"
#include "common_game.h"
#include "config.h"
#include "function.h"

#include "rts.h"

short GamePlays = 0;

/*
===================
=
= SetGameDefaults
=
===================
*/

void SetGameDefaults(void)
{
}

extern SWBOOL DrawScreen;

void EncodePassword(char *pw)
{
    int bak_DrawScreen = DrawScreen;
    int bak_randomseed = randomseed;
    int i;
    int len;

    DrawScreen = FALSE;
    randomseed = 1234L;

    Bstrupr(pw);

    len = strlen(pw);
    for (i = 0; i < len; i++)
        pw[i] += RANDOM_RANGE(26);

    randomseed = bak_randomseed;
    DrawScreen = bak_DrawScreen;
}

void DecodePassword(char *pw)
{
    int bak_DrawScreen = DrawScreen;
    int bak_randomseed = randomseed;
    int i;
    int len;

    DrawScreen = FALSE;
    randomseed = 1234L;

    Bstrupr(pw);

    len = strlen(pw);
    for (i = 0; i < len; i++)
        pw[i] -= RANDOM_RANGE(26);

    randomseed = bak_randomseed;
    DrawScreen = bak_DrawScreen;
}

/*
===================
=
= ReadGameSetup
=
===================
*/

void ReadGameSetup(int32_t scripthandle)
{
    int dummy;
    extern char WangBangMacro[10][64];

    for (dummy = 0; dummy < 10; dummy++)
    {
        sprintf(ds,"CommbatMacro#%d",dummy);
        SCRIPT_GetString(scripthandle, "Comm Setup",ds,WangBangMacro[dummy]);
    }

    SCRIPT_GetString(scripthandle, "Options","Rooster",gs.Password);
    DecodePassword(gs.Password);

    // option stuff
    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "BorderNum",&dummy);
    if (dummy != -1) gs.BorderNum = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Brightness",&dummy);
    if (dummy != -1) gs.Brightness = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "BorderTile",&dummy);
    if (dummy != -1) gs.BorderTile = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Bobbing",&dummy);
    if (dummy != -1) gs.Bobbing = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Tilting",&dummy);
    if (dummy != -1) gs.Tilting = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Shadows",&dummy);
    if (dummy != -1) gs.Shadows = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "AutoRun",&dummy);
    if (dummy != -1) gs.AutoRun = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Crosshair",&dummy);
    if (dummy != -1) gs.Crosshair = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "AutoAim",&dummy);
    if (dummy != -1) gs.AutoAim = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "InterpolateSO",&dummy);
    if (dummy != -1) gs.InterpolateSO = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Messages",&dummy);
    if (dummy != -1) gs.Messages = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Talking",&dummy);
    if (dummy != -1) gs.Talking = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Ambient",&dummy);
    if (dummy != -1) gs.Ambient = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "FxOn",&dummy);
    if (dummy != -1) gs.FxOn = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "MusicOn",&dummy);
    if (dummy != -1) gs.MusicOn = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Controls", "MouseAiming",&dummy);
    if (dummy != -1) gs.MouseAimingType = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "NetGameType",&dummy);
    if (dummy != -1) gs.NetGameType = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "NetLevel",&dummy);
    if (dummy != -1) gs.NetLevel = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "NetMonsters",&dummy);
    if (dummy != -1) gs.NetMonsters = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "NetHurtTeammate",&dummy);
    if (dummy != -1) gs.NetHurtTeammate = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "NetSpawnMarkers",&dummy);
    if (dummy != -1) gs.NetSpawnMarkers = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "NetTeamPlay",&dummy);
    if (dummy != -1) gs.NetTeamPlay = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "NetKillLimit",&dummy);
    if (dummy != -1) gs.NetKillLimit = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "NetTimeLimit",&dummy);
    if (dummy != -1) gs.NetTimeLimit = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "NetColor",&dummy);
    if (dummy != -1) gs.NetColor = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Voxels",&dummy);
    if (dummy != -1) gs.Voxels = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Stats",&dummy);
    if (dummy != -1) gs.Stats = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Darts",&dummy);
    if (dummy != -1) gs.Darts = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "WeaponAutoSwitch",&dummy);
    if (dummy != -1) gs.WeaponAutoSwitch = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "FOV",&dummy);
    if (dummy != -1) gs.FOV = clamp(dummy, MinFOV, MaxFOV);

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "MouseAimingOn",&dummy);
    if (dummy != -1) gs.MouseAimingOn = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "MouseInvert",&dummy);
    if (dummy != -1) gs.MouseInvert = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "Kiwi",&dummy);
    if (dummy != -1) gs.ParentalLock = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "PlayCD",&dummy);
    if (dummy != -1) gs.PlayCD = dummy;

    dummy = -1;
    SCRIPT_GetNumber(scripthandle, "Options", "CDDevice",&dummy);
    if (dummy < 0) dummy = -1;

    if (SW_SHAREWARE)
    {
        dummy = -1;
        SCRIPT_GetNumber(scripthandle, "Options", "Chickens",&dummy);
        if (dummy != -1) GamePlays = dummy;

        buildprintf(
            "\n"
            "You have played Shadow Warrior %d times.  Please call and order the full\n"
            "version at 1(800)-3DREALMS or see the ORDER.FRM file.\n\n"
            ,GamePlays);

        GamePlays++;
    }
}

/*
===================
=
= WriteGameSetup
=
===================
*/

void WriteGameSetup(int32_t scripthandle)
{
    int dummy;

    dummy = gs.BorderNum;
    SCRIPT_PutNumber(scripthandle, "Options", "BorderNum",dummy,FALSE,FALSE);
    dummy = gs.Brightness;
    SCRIPT_PutNumber(scripthandle, "Options", "Brightness",dummy,FALSE,FALSE);
    dummy = gs.BorderTile;
    SCRIPT_PutNumber(scripthandle, "Options", "BorderTile",dummy,FALSE,FALSE);
    dummy = gs.Bobbing;
    SCRIPT_PutNumber(scripthandle, "Options", "Bobbing",dummy,FALSE,FALSE);
    dummy = gs.Tilting;
    SCRIPT_PutNumber(scripthandle, "Options", "Tilting",dummy,FALSE,FALSE);
    dummy = gs.Shadows;
    SCRIPT_PutNumber(scripthandle, "Options", "Shadows",dummy,FALSE,FALSE);
    dummy = gs.AutoRun;
    SCRIPT_PutNumber(scripthandle, "Options", "AutoRun",dummy,FALSE,FALSE);
    dummy = gs.Crosshair;
    SCRIPT_PutNumber(scripthandle, "Options", "Crosshair",dummy,FALSE,FALSE);
    dummy = gs.AutoAim;
    SCRIPT_PutNumber(scripthandle, "Options", "AutoAim",dummy,FALSE,FALSE);
    dummy = gs.InterpolateSO;
    SCRIPT_PutNumber(scripthandle, "Options", "InterpolateSO",dummy,FALSE,FALSE);
    dummy = gs.Messages;
    SCRIPT_PutNumber(scripthandle, "Options", "Messages",dummy,FALSE,FALSE);
    dummy = gs.Talking;
    SCRIPT_PutNumber(scripthandle, "Options", "Talking",dummy,FALSE,FALSE);
    dummy = gs.Ambient;
    SCRIPT_PutNumber(scripthandle, "Options", "Ambient",dummy,FALSE,FALSE);
    dummy = gs.FxOn;
    SCRIPT_PutNumber(scripthandle, "Options", "FxOn",dummy,FALSE,FALSE);
    dummy = gs.MouseAimingType;
    SCRIPT_PutNumber(scripthandle, "Controls", "MouseAiming",dummy,FALSE,FALSE);

    dummy = gs.MusicOn;
    SCRIPT_PutNumber(scripthandle, "Options", "MusicOn",dummy,FALSE,FALSE);

    dummy = gs.NetGameType;
    SCRIPT_PutNumber(scripthandle, "Options", "NetGameType",dummy,FALSE,FALSE);
    dummy = gs.NetLevel;
    SCRIPT_PutNumber(scripthandle, "Options", "NetLevel",dummy,FALSE,FALSE);
    dummy = gs.NetMonsters;
    SCRIPT_PutNumber(scripthandle, "Options", "NetMonsters",dummy,FALSE,FALSE);
    dummy = gs.NetHurtTeammate;
    SCRIPT_PutNumber(scripthandle, "Options", "NetHurtTeammate",dummy,FALSE,FALSE);
    dummy = gs.NetSpawnMarkers;
    SCRIPT_PutNumber(scripthandle, "Options", "NetSpawnMarkers",dummy,FALSE,FALSE);
    dummy = gs.NetTeamPlay;
    SCRIPT_PutNumber(scripthandle, "Options", "NetTeamPlay",dummy,FALSE,FALSE);
    dummy = gs.NetKillLimit;
    SCRIPT_PutNumber(scripthandle, "Options", "NetKillLimit",dummy,FALSE,FALSE);
    dummy = gs.NetTimeLimit;
    SCRIPT_PutNumber(scripthandle, "Options", "NetTimeLimit",dummy,FALSE,FALSE);
    dummy = gs.NetColor;
    SCRIPT_PutNumber(scripthandle, "Options", "NetColor",dummy,FALSE,FALSE);
    dummy = gs.Voxels;
    SCRIPT_PutNumber(scripthandle, "Options", "Voxels",dummy,FALSE,FALSE);
    dummy = gs.MouseAimingOn;
    SCRIPT_PutNumber(scripthandle, "Options", "MouseAimingOn",dummy,FALSE,FALSE);
    dummy = gs.MouseInvert;
    SCRIPT_PutNumber(scripthandle, "Options", "MouseInvert",dummy,FALSE,FALSE);
    dummy = gs.Stats;
    SCRIPT_PutNumber(scripthandle, "Options", "Stats",dummy,FALSE,FALSE);
    dummy = gs.Darts;
    SCRIPT_PutNumber(scripthandle, "Options", "Darts",dummy,FALSE,FALSE);
    dummy = gs.WeaponAutoSwitch;
    SCRIPT_PutNumber(scripthandle, "Options", "WeaponAutoSwitch",dummy,FALSE,FALSE);
    dummy = gs.FOV;
    SCRIPT_PutNumber(scripthandle, "Options", "FOV",dummy,FALSE,FALSE);

    EncodePassword(gs.Password);
    SCRIPT_PutString(scripthandle, "Options","Rooster",gs.Password);
    DecodePassword(gs.Password);

    dummy = gs.ParentalLock;
    SCRIPT_PutNumber(scripthandle, "Options", "Kiwi",dummy,FALSE,FALSE);

    dummy = gs.PlayCD;
    SCRIPT_PutNumber(scripthandle, "Options", "PlayCD",dummy,FALSE,FALSE);
    SCRIPT_PutNumber(scripthandle, "Options", "CDDevice",0,FALSE,FALSE);

    if (SW_SHAREWARE)
    {
        dummy = GamePlays;
        SCRIPT_PutNumber(scripthandle, "Options", "Chickens",dummy,FALSE,FALSE);
    }
}

void TermSetup(void)
{
    CONFIG_WriteSetup();
    RTS_Shutdown();
}


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 1997, 2005 - 3D Realms Entertainment

This file is part of Shadow Warrior version 1.2

Shadow Warrior is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

Original Source: 1997 - Frank Maddin and Jim Norwood
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------
#include "build.h"

#include "keys.h"
#include "game.h"
#include "tags.h"
#include "names2.h"
#include "network.h"
#include "menus.h"

SWBOOL SyncPrintMode = TRUE;
short NumSyncBytes = 1;
char sync_first[MAXSYNCBYTES][60];
int sync_found = FALSE;

static int crctable[256];
#define updatecrc(dcrc,xz) (dcrc = (crctable[((dcrc)>>8)^((xz)&255)]^((dcrc)<<8)))

void initsynccrc(void)
{
    int i, j, k, a;

    for (j=0; j<256; j++)   //Calculate CRC table
    {
        k = (j<<8); a = 0;
        for (i=7; i>=0; i--)
        {
            if (((k^a)&0x8000) > 0)
                a = ((a<<1)&65535) ^ 0x1021;   //0x1021 = genpoly
            else
                a = ((a<<1)&65535);
            k = ((k<<1)&65535);
        }
        crctable[j] = (a&65535);
    }
}

#if SYNC_TEST
uint8_t
PlayerSync(void)
{
    short i;
    unsigned short crc = 0;
    PLAYERp pp;

    for (i = connecthead; i >= 0; i = connectpoint2[i])
    {
        pp = Player + i;
        updatecrc(crc, pp->posx & 255);
        updatecrc(crc, pp->posy & 255);
        updatecrc(crc, pp->posz & 255);
        updatecrc(crc, fix16_to_int(pp->q16ang) & 255);
    }

    return (uint8_t) crc & 255;
}

uint8_t
PlayerSync2(void)
{
    short i;
    unsigned short crc = 0;
    PLAYERp pp;

    for (i = connecthead; i >= 0; i = connectpoint2[i])
    {
        pp = Player + i;

        updatecrc(crc, fix16_to_int(pp->q16horiz) & 255);
        updatecrc(crc, User[pp->PlayerSprite]->Health & 255);
        updatecrc(crc, pp->bcnt & 255);
    }

    return (uint8_t) crc & 255;
}

uint8_t
SOSync(void)
{
    unsigned short crc = 0;
    SECTOR_OBJECTp sop;

    for (sop = SectorObject; sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++)
    {
        updatecrc(crc, (sop->xmid) & 255);
        updatecrc(crc, (sop->ymid) & 255);
        updatecrc(crc, (sop->zmid) & 255);
        updatecrc(crc, (sop->vel) & 255);
        updatecrc(crc, (sop->ang) & 255);
        updatecrc(crc, (sop->ang_moving) & 255);
        updatecrc(crc, (sop->spin_ang) & 255);
    }

    return (uint8_t) crc & 255;
}

uint8_t
EnemySync(void)
{
    unsigned short crc = 0;
    short j, nextj;
    SPRITEp spr;

    TRAVERSE_SPRITE_STAT(headspritestat[STAT_ENEMY], j, nextj)
    {
        spr = &sprite[j];
        updatecrc(crc, (spr->x) & 255);
        updatecrc(crc, (spr->y) & 255);
        updatecrc(crc, (spr->z) & 255);
        updatecrc(crc, (spr->ang) & 255);
    }

#if 0
    extern char DemoTmpName[];
    //DSPRINTF(ds, "Demo Tmp Name %s", DemoTmpName);
    MONO_PRINT(ds);

    {
        if (Once < 1 && DemoTmpName[0] != '\0')
        {
            FILE *fout;

            Once++;
            fout = fopen(DemoTmpName, "wb");

            //DSPRINTF(ds, "Demo Tmp Name %s", DemoTmpName);
            MONO_PRINT(ds);

            TRAVERSE_SPRITE_STAT(headspritestat[STAT_ENEMY], j, nextj)
            {
                spr = &sprite[j];

                fprintf(fout, "num %d, spr->x %d, spr->y %d, spr->z %d, spr->ang %d, spr->picnum %d\n", j, spr->x, spr->y, spr->z, spr->ang, spr->picnum);
            }
            fclose(fout);
        }
    }
#endif

    return (uint8_t) crc & 255;
}

uint8_t
MissileSync(void)
{
    unsigned short crc = 0;
    short j, nextj;
    SPRITEp spr;

    TRAVERSE_SPRITE_STAT(headspritestat[STAT_MISSILE], j, nextj)
    {
        spr = &sprite[j];
        updatecrc(crc, (spr->x) & 255);
        updatecrc(crc, (spr->y) & 255);
        updatecrc(crc, (spr->z) & 255);
        updatecrc(crc, (spr->ang) & 255);
    }

    return (uint8_t) crc & 255;
}

uint8_t
MissileSkip4Sync(void)
{
    unsigned short crc = 0;
    short j, nextj;
    SPRITEp spr;

    TRAVERSE_SPRITE_STAT(headspritestat[STAT_MISSILE_SKIP4], j, nextj)
    {
        spr = &sprite[j];
        updatecrc(crc, (spr->x) & 255);
        updatecrc(crc, (spr->y) & 255);
        updatecrc(crc, (spr->z) & 255);
        updatecrc(crc, (spr->ang) & 255);
    }

    return (uint8_t) crc & 255;
}

uint8_t
ShrapSync(void)
{
    unsigned short crc = 0;
    short j, nextj;
    SPRITEp spr;

    TRAVERSE_SPRITE_STAT(headspritestat[STAT_SHRAP], j, nextj)
    {
        spr = &sprite[j];
        updatecrc(crc, (spr->x) & 255);
        updatecrc(crc, (spr->y) & 255);
        updatecrc(crc, (spr->z) & 255);
        updatecrc(crc, (spr->ang) & 255);
    }

    return (uint8_t) crc & 255;
}

uint8_t
MiscSync(void)
{
    unsigned short crc = 0;
    short j, nextj;
    SPRITEp spr;

    TRAVERSE_SPRITE_STAT(headspritestat[STAT_MISC], j, nextj)
    {
        spr = &sprite[j];
        updatecrc(crc, (spr->x) & 255);
        updatecrc(crc, (spr->y) & 255);
        updatecrc(crc, (spr->z) & 255);
        updatecrc(crc, (spr->ang) & 255);
    }

    return (uint8_t) crc & 255;
}

uint8_t
RandomSync(void)
{
    unsigned short crc = 0;

    updatecrc(crc, randomseed & 255);
    updatecrc(crc, (randomseed >> 8) & 255);

    if (NumSyncBytes == 1)
    {
        updatecrc(crc,PlayerSync() & 255);
        updatecrc(crc,PlayerSync2() & 255);
        updatecrc(crc,MissileSync() & 255);
    }

    return (uint8_t) crc & 255;
}

/*
#define STAT_SKIP2_START    2
#define STAT_ENEMY          2
#define STAT_DEAD_ACTOR     3 //misc actor stuff - dead guys etc
#define STAT_MISSILE        4
#define STAT_SKIP2_END      4

#define STAT_SKIP4_START    5
#define STAT_ITEM           5
#define STAT_SKIP4          6
#define STAT_MISSILE_SKIP4  7
#define STAT_ENEMY_SKIP4    8
#define STAT_SKIP4_END      8
*/

const char *SyncNames[] =
{
    "RandomSync",
    "PlayerSync",
    "PlayerSync2",
    "SOSync",
    "EnemySync",
    "MissileSync",
    "ShrapSync",
    "MiscSync",
    "MissileSkip4Sync",
    NULL
};

static uint8_t(*SyncFunc[MAXSYNCBYTES + 1]) (void) =
{
    RandomSync,
    PlayerSync,
    PlayerSync2,
    SOSync,
    EnemySync,
    MissileSync,
    ShrapSync,
    MiscSync,
    MissileSkip4Sync,
    NULL
};

void
getsyncstat(void)
{
    int i;
    PLAYERp pp = Player + myconnectindex;
    unsigned int val;
    static unsigned int count;

    if (!CommEnabled)
        return;

    if (numplayers < 2)
        return;

    for (i = 0; SyncFunc[i]; i++)
    {
        pp->syncval[pp->syncvalhead & (SYNCFIFOSIZ - 1)][i] = (*SyncFunc[i])();
    }

    val = pp->syncval[pp->syncvalhead & (SYNCFIFOSIZ - 1)][0];
    count += val;

    pp->syncvalhead++;
}

////////////////////////////////////////////////////////////////////////
//
// Sync Message print
//
////////////////////////////////////////////////////////////////////////

void
SyncStatMessage(void)
{
    int i, j;
    static unsigned int MoveCount = 0;
    extern unsigned int MoveThingsCount;

    if (!CommEnabled)
        return;

    if (!SyncPrintMode)
        return;

    if (numplayers <= 1)
        return;

    for (i = 0; i < NumSyncBytes; i++)
    {
        // syncstat is NON 0 - out of sync
        if (syncstat[i] != 0)
        {
            if (NumSyncBytes > 1)
            {
                sprintf(ds, "GAME OUT OF SYNC - %s", SyncNames[i]);
                printext256(68L, 68L + (i * 8), 1, 31, ds, 0);
            }

            if (!sync_found && sync_first[i][0] == '\0')
            {
                // sync_found one so test all of them and then never test again
                sync_found = TRUE;

                // save off loop count
                MoveCount = MoveThingsCount;

                for (j = 0; j < NumSyncBytes; j++)
                {
                    if (syncstat[j] != 0 && sync_first[j][0] == '\0')
                    {
                        sprintf(ds, "OUT OF SYNC - %s", SyncNames[j]);
                        strcpy(sync_first[j], ds);
                    }
                }
            }
        }
    }

    // print out the sync_first message you got
    for (i = 0; i < NumSyncBytes; i++)
    {
        if (sync_first[i][0] != '\0')
        {
            if (NumSyncBytes > 1)
            {
                sprintf(ds, "FIRST %s", sync_first[i]);
                printext256(50L, 0L, 1, 31, ds, 0);
                sprintf(ds, "MoveCount %u",MoveCount);
                printext256(50L, 10L, 1, 31, ds, 0);
            }
            else
            {
                short w,h;
                // production out of sync error

                sprintf(ds,"GAME OUT OF SYNC!");
                MNU_MeasureString(ds, &w, &h);
                MNU_DrawString(TEXT_TEST_COL(w), 20, ds, 0, 19);

                sprintf(ds,"Restart the game.");
                MNU_MeasureString(ds, &w, &h);
                MNU_DrawString(TEXT_TEST_COL(w), 30, ds, 0, 19);
            }
        }
    }

    if (syncstate != 0)
        printext256(68L, 92L, 1, 31, "Missed Network packet!", 0);
}

void
GetSyncInfoFromPacket(uint8_t *packbuf, int packbufleng, int *j, int otherconnectindex)
{
    int sb, i;
    extern int syncvaltottail;
    PLAYERp ppo = &Player[otherconnectindex];
    SWBOOL found = FALSE;

    // have had problems with this routine crashing when players quit
    // games.

    // if ready2send is not set then don't try to get sync info

    if (!ready2send)
        return;

    // Suspect that its trying to traverse the connect list
    // for a player that does not exist.  This tries to take care of that

    TRAVERSE_CONNECT(i)
    {
        if (otherconnectindex == i)
            found = TRUE;
    }

    if (!found)
        return;

    // sync testing
    //while ((*j) != packbufleng) // changed this on Kens suggestion
    while ((*j) < packbufleng)
    {
        for (sb = 0; sb < NumSyncBytes; sb++)
        {
            ppo->syncval[ppo->syncvalhead & (SYNCFIFOSIZ - 1)][sb] = packbuf[(*j)++];
        }
        ppo->syncvalhead++;
    }

    // update syncstat
    // if any of the syncstat vars is non-0 then there is a problem
    TRAVERSE_CONNECT(i)
    {
        if (Player[i].syncvalhead == syncvaltottail)
            return;
    }

    //for (sb = 0; sb < NumSyncBytes; sb++)
    //    syncstat[sb] = 0;

    while (TRUE)
    {
        for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
        {
            for (sb = 0; sb < NumSyncBytes; sb++)
            {
                if (Player[i].syncval[syncvaltottail & (SYNCFIFOSIZ - 1)][sb] != Player[connecthead].syncval[syncvaltottail & (SYNCFIFOSIZ - 1)][sb])
                {
                    syncstat[sb] = 1;
                }
            }
        }

        syncvaltottail++;

        TRAVERSE_CONNECT(i)
        {
            if (Player[i].syncvalhead == syncvaltottail)
                return;
        }
    }
}

////////////////////////////////////////////////////////////////////////
//
// Demo Sync recording and testing
//
////////////////////////////////////////////////////////////////////////

extern FILE *DemoSyncFile;

void
demosync_record(void)
{
    int i;
    uint8_t sync_val;

    for (i = 0; SyncFunc[i]; i++)
    {
        sync_val = (*SyncFunc[i])();
        fwrite(&sync_val, sizeof(sync_val), 1, DemoSyncFile);
    }
}

void
demosync_test(int cnt)
{
    int i;
    uint8_t sync_val;

    for (i = 0; SyncFunc[i]; i++)
    {
        fread(&sync_val, sizeof(sync_val), 1, DemoSyncFile);

        if (sync_val != (*SyncFunc[i])())
        {
            TerminateLevel();
            TerminateGame();
            printf("Demo out of sync - Sync Byte Number %d - Iteration %d.", i, cnt);
            exit(0);
        }
    }
}

/*
getsyncbyte()
    {
    int i, j;
    char ch;
    SPRITEp spr;
    PLAYERp pp;
    USERp u;

    ch = (char) (randomseed & 255);

    for (i = connecthead; i >= 0; i = connectpoint2[i])
        {
        pp = Player + i;
        u = User[pp->SpriteP - sprite];
        ch ^= (pp->posx ^ pp->posy ^ pp->posz ^ fix16_to_int(pp->q16ang) ^ fix16_to_int(pp->q16horiz) ^ u->Health);
        }

    for (j = headspritestat[STAT_ENEMY]; j >= 0; j = nextspritestat[j])
        {
        spr = &sprite[j];
        ch ^= spr->x ^ spr->y ^ spr->z ^ spr->ang;
        }

    return (ch);
    }
*/
#endif

repo_name: orochi/nblood

license: mit


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 1997, 2005 - 3D Realms Entertainment

This file is part of Shadow Warrior version 1.2

Shadow Warrior is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

Original Source: 1997 - Frank Maddin and Jim Norwood
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------

#ifndef TAGS_H
#define TAGS_H

#include "jtags.h"

// NOTE: Switches are always sprites and are usually on walls, triggers are on the floor.

//////////////////////////////////////////////////////////////////////////////////////////
//
// MISC TAGS
//
//////////////////////////////////////////////////////////////////////////////////////////

// Stepping on this finds actors closeby that are on a track at a point defined as
// TRACK_ACTOR_WAIT_FOR_TRIGGER and activates them.
// High tag = distance to look for actors
#define TAG_TRIGGER_ACTORS      3

// For ladders attached to white walls.
#define TAG_LADDER              30

//Shoots a fireball from a ST1 FIREBALL_TRAP (or BOLT) sprite with a matching number.
//High tag = match number to match with ST1 sprite
#define TAG_TRIGGER_MISSILE_TRAP 43

//Explodes wall sector
//High tag = match number
#define TAG_TRIGGER_EXPLODING_SECTOR 44

//////////////////////////////////////////////////////////////////////////////////////////
//
// DOOR TAGS
//
//////////////////////////////////////////////////////////////////////////////////////////

// High tag for z moving doors is always the speed unless otherwise noted - default
// 200

// Red sector rotating doors.  They can have up to 15 points per door and
// rotate about any point you choose.  Don't have to be rectangular, can be any shape.  Can
// use masked walls with them.

// Red sector rotating door - Master sector that has doors inside of it
// To lock these types of doors place a SECT_LOCK_DOOR ST1 in this sector
#define TAG_DOOR_ROTATE         112

// Red sector rotating door - Tag the actual door with this. Rotate POSITIVE or NEGATIVE 90 degrees
#define TAG_DOOR_ROTATE_POS     113
#define TAG_DOOR_ROTATE_NEG     114

// Wall pivot point - MUST tag the ouside of the wall, NOT the inside!! - red sector method
//  Remember - a wall is just an x,y location
#define TAG_WALL_ROTATE_PIVOT 2

// Tag for sliding door (Star Trek/Wolf type)
#define TAG_DOOR_SLIDING        115
// Wall tag for sliding door placed on the end of the door
#define TAG_WALL_SLIDING_DOOR 10

// Tag for exiting current level and starting up another one.
// High Tag - Destination level number -
// 0 - Title screen
// 1 - e1l1
// 2 - e1l2
// ...
#define TAG_LEVEL_EXIT_SWITCH 116

//////////////////////////////////////////////////////////////////////////////////////////
//
// ELEVATOR TAGS
//
//////////////////////////////////////////////////////////////////////////////////////////

// Mappers DONT use this!!  Use ST1 SECT_VATOR.
#define TAG_VATOR 206

// toggles ST1 SECT_VATOR sectors
// TAG1 = match tag
#define TAG_SPRITE_SWITCH_VATOR   206
#define TAG_SECTOR_TRIGGER_VATOR  206

// toggles ST1 SCALE sector objects
// TAG1 = match tag
#define TAG_SO_SCALE_SWITCH 208
#define TAG_SO_SCALE_TRIGGER 208

// toggles ST1 SCALE sector objects
// TAG1 = match tag
#define TAG_SO_SCALE_ONCE_SWITCH 209
#define TAG_SO_SCALE_ONCE_TRIGGER 209

// TAG1 = match tag
#define TAG_LIGHT_SWITCH 210
#define TAG_LIGHT_TRIGGER 210

// EVERTHING tags will trigger everything with a match tag
// TAG1 = match tag
#define TAG_SWITCH_EVERYTHING 211
#define TAG_TRIGGER_EVERYTHING 211

// TAG1 = match tag
#define TAG_SWITCH_EVERYTHING_ONCE 212
#define TAG_TRIGGER_EVERYTHING_ONCE 212

#define TAG_COMBO_SWITCH_EVERYTHING 213
#define TAG_COMBO_SWITCH_EVERYTHING_ONCE 214

// High tag is the number to MATCH the ST1 match number.
#define TAG_SO_EVENT_SWITCH   215
// Same as switch but tag a sector as a trigger.
#define TAG_SO_EVENT_TRIGGER  215

// Spawns sprites with matching tags
// Same as switch but tag a sector as a trigger.
#define TAG_SPAWN_ACTOR_TRIGGER  216

// Spawns sprites with matching tags
// Same as switch but tag a sector as a trigger.
#define TAG_SECRET_AREA_TRIGGER  217

#define TAG_ROTATOR  218
#define TAG_SLIDOR  220
// wall tags for SLIDOR
// hitag = match
#define TAG_WALL_SLIDOR_LEFT    220
#define TAG_WALL_SLIDOR_RIGHT   221
#define TAG_WALL_SLIDOR_UP      222
#define TAG_WALL_SLIDOR_DOWN    223

// Step on the sector, press the space bar, and it shoves you high into the air.
// High tag has height of jump
#define TAG_SPRING_BOARD        240

// Sine wave floor effect - max 5 per level
//
// Tag the first sector with 400, the next with 401, and so on up to 419.
// The WAVE will actually flow from the opposite end.  The WAVE direction is what is
// refered to when BEGINNING and END are referred to below.
//
// 1st Sector High Tag = the range in pixels the floor will undulate in the Z direction
// 2rd Sector High Tag = range decrement - takes the range from the 1st sector high tag and
//                       adjusts all the rest by this decrement - makes the WAVE start off
//                       small and get LARGER toward the end - THIS IS IN Z COORDINATES
//                       *NOT* PIXELS
// 3nd Sector High Tag = speed of the motion - a shift value - default to 3
// 4th Sector High Tag = a distance from one peak (top of curve) to the next - default is the
//                       number of sectors in the SINE WAVE (max of 20)
// Last Sector High Tag= special tag to make a realistic ocean wave - modifies the range
//                       toward the END (greatest range is usually here) of the WAVE
//                       so that it dissapates quickly. Without this it would just continue
//                       to get bigger toward the end of the WAVE.

#define TAG_SINE_WAVE_FLOOR     400
#define TAG_SINE_WAVE_CEILING   420
#define TAG_SINE_WAVE_BOTH      440

//////////////////////////////////////////////////////////////////////////////////////////
//
// SECTOR OBJECT TAGS
//
//////////////////////////////////////////////////////////////////////////////////////////
// Sector Objects (SOs) are groups of sectors that can be moved around on a track.
// All SOs must have at a minimum:
//      1. Bounding sprites (upper left and lower right) that contains all sectors to be moved.
//      2. A sector marked as the center of the SO.
//
// Tags 500-600 are set reserved for SOs.  There is a maximum of 20 SOs per level.
//
// Tags 500-504 correspond to object 1, 505-509 to object 2, 510-514 to object 3, etc ...
//
// Bounding sprite tags are set up similar.
//      Upper left tag of object 1 is 500, lower right is 501
//      Upper left tag of object 2 is 505, lower right is 506
//      Etc...
//////////////////////////////////////////////////////////////////////////////////////////

// The center of this sector will be the center of the SO
// IMPORTANT: High Tag must be set to the track number
#define TAG_OBJECT_CENTER       501

//////////////////////////////////////////////////////////////////////////////////////////
//
// TRACK TAGS FOR SECTOR OBJECTS
//
//////////////////////////////////////////////////////////////////////////////////////////
// Tracks allow SOs and sprites to follow a path designated by the map-maker.
// All Tracks must have at a minimum:
//      1. A TRACK_START.
//      2. A TRACK_END.
//
// Tracks are set up by the program by connecting sprites placed by the map-maker in the BUILD
// editor.  The track sprites start at location 1900 and end at 1999 so there are 100 available
// tracks.  Tracks automatically loop back to the beginning when the TRACK_END sprite is
// detected.  Track tags listed below can be set to modify the behavior of objects moving along
// them.
//
// Look at the tracks in example maps to see how they are placed.
//
// NOTE: Track direction is dependent on the next closest sprite to the TRACK_START sprite.
// As noted below, certain track tags are dependant on the direction the object is traveling on
// on the track.
//
// For placing actor sprite on the tracks:
//      1. Put a sprite down near the point you want it to start from.
//      2. Adjust the angle to the left to make the sprite move in the "reverse" direction
//         and to the right to make the sprite move in the "forward" direction.
//      3. For the pic, place the first pic of the actor found in the editart file.
//
// Every track can have a type set in the high tag of TRACK_START.
//////////////////////////////////////////////////////////////////////////////////////////

// Mark first track sprite with this
// High tag = Type of track (defined next)
#define TRACK_START             700

//
// TRACK TYPES - only valid for sprites only NOT for SOs
//
// Used to attach a name to a track purpose.  The actors will "look around" for
// tracks to know what actions are available to them.
//

// All tracks are assumed to be SEGMENTS (non-circular, generally leading in a certain
// direction) unless otherwise noted.  SEGMENTS are generally kept short with a few
// exceptions.

// Follow a circular route available for sprites to hop on and off.
// Generally covers a larger area than TT_WANDER.
#define TT_ROUTE            1

// Jump up only
#define TT_JUMP_UP          2
// Jump down only
#define TT_JUMP_DOWN        3
// Jump up/down track
#define TT_JUMP_BOTH        4
// Ladder track.  Currently only good for going up.  Must jump down.
#define TT_LADDER           5
// Stair track.  Hard for sprites to maneuver narrow stairs well without tracks.
#define TT_STAIRS           6

// Traverse a complex route - generally thought of to move you from point A to point B
// in complex map situations.
#define TT_TRAVERSE         7

// Duck behind cover and attack
#define TT_DUCK_N_SHOOT     8
// Hide behind cover and attack
#define TT_HIDE_N_SHOOT     9

// Exit tracks to exit a room/area.  Probably should lead to a door alot of the time.
#define TT_EXIT             10

// Wander track. Wander about general area until you come upon a player.
#define TT_WANDER           11

// Scan for other tracks.  Generally a VERY short track put these in places where
// other tracks can be seen easily.  Good "vantage points".
#define TT_SCAN             12

// Super Jump
#define TT_SUPER_JUMP_UP    13

// Operate Stuff
#define TT_OPERATE          14

// Mark last sprite with this
#define TRACK_END               701
// Set the target speed and actual speed at this point
// Valid values for target speed are 2 to 128
#define TRACK_SET_SPEED         702
// Stop for (seconds) in high tag
#define TRACK_STOP              703
// Reverse the direction
#define TRACK_REVERSE           704

// Note that the next two tags have the opposite effect when traveling the REVERSE direction

// Sets up a target speed by a delta (amt) in high tag
// velocity = (current target velocity) + (speed up amount in high tag)
// Valid values for target speed are 2 to 128
#define TRACK_SPEED_UP          705

// Sets up a target speed by a delta (amt) in high tag
// velocity = (current target velocity) - (speed up amount in high tag)
// Valid values for target speed are 2 to 128
#define TRACK_SLOW_DOWN         706

// The rate at which the velocity approaches the target speed.
// This is defined as a shift value (for processing speed) and defaults to 6.  The valid range
// is 1 to 12.
#define TRACK_VEL_RATE          707

// Moves the floor of the object by a delta PIXEL position (amt) in high tag
#define TRACK_ZUP               709
// Moves the floor of the object by a delta PIXEL position (amt) in high tag
#define TRACK_ZDOWN             710
// Sets the rate at which the ZUP/ZDOWN moves. Defaults to 256.
#define TRACK_ZRATE             711
// Special mode where the object looks at the zcoord of the next track point and moves
// to achieve the destination.  In high tag is a negative delta Z from the placement of
// the track sprites z value.
#define TRACK_ZDIFF_MODE        712

// Object spins as it goes along its track.  Spin speed in high tag.
// For now, once you start it spinning you cannot stop it.
#define TRACK_SPIN              715

// Object stops spining.  Angle to finish at in high tag.
#define TRACK_SPIN_STOP         716

// Bobbing for SO's.
// High tag = Bob amt in pixels.
#define TRACK_BOB_START         717
// High tag = Bob speed - shift amt pixels.
#define TRACK_BOB_SPEED         718
// Bobbing for SO's.
#define TRACK_BOB_STOP          719
// Start object spinning in the opposite direction.
#define TRACK_SPIN_REVERSE      720

// Start object sinking to ST1 SECT_SO_SINK_DEST
// For boats
// High tag = speed of sinking
#define TRACK_SO_SINK           723

// For boats - lower whirlpool sector - tagged with ST1 SECT_SO_FORM_WHIRLPOOL
#define TRACK_SO_FORM_WHIRLPOOL   724

// Move Sprite Objects (not sector objects) straight up or down in the z
// direction to the next points z height then continues along the track
// High tag = speed of movement - default is 256
#define TRACK_MOVE_VERTICAL    725

// Object will wait at this point on the track for a trigger/switch to be
// flipped.  Use TAG_SO_EVENT_SWITCH and TRIGGER to free the SO to
// continue. In addition the these switches and triggers, others that have
// have MATCHing tags will work with this tag.  The following is a list.
//
// TAG_SPRITE_HIT_MATCH
// TAG_OPEN_DOOR_SWITCH
// TAG_OPEN_DOOR_TRIGGER
//
// Basically anthing that has a match tag that operates on sectors can also
// operate a TRACK_WAIT_FOR_EVENT.
//

// High tag = match number
#define TRACK_WAIT_FOR_EVENT   726

// does a DoMatchEverything
// TAG1 = match tag
#define TRACK_MATCH_EVERYTHING 728
#define TRACK_MATCH_EVERYTHING_ONCE 729

///////////////
//
// TRACK TAGS FOR SPRITES ONLY
//
///////////////

// Set the target speed and actual speed at this point
// Valid values for target speed are 2 to 128
#define TRACK_ACTOR_SET_SPEED         750
// Stop for (seconds) in high tag
#define TRACK_ACTOR_STOP              751
// Reverse the direction
#define TRACK_ACTOR_REVERSE           752

// Note that the next two tags have the opposite effect when traveling the REVERSE direction

// Sets up a target speed by a delta (amt) in high tag
// velocity = (current target velocity) + (speed up amount in high tag)
// Valid values for target speed are 2 to 128
#define TRACK_ACTOR_SPEED_UP          753

// Sets up a target speed by a delta (amt) in high tag
// velocity = (current target velocity) - (speed up amount in high tag)
// Valid values for target speed are 2 to 128
#define TRACK_ACTOR_SLOW_DOWN         754

// The rate at which the velocity approaches the target speed.
// This is defined as a shift value (for processing speed) and defaults to 6.  The valid range
// is 1 to 12.
#define TRACK_ACTOR_VEL_RATE          755

// Special mode where the object looks at the zcoord of the next track point and moves
// to achieve the destination.  Should not be set when jumping/climbing etc.
#define TRACK_ACTOR_ZDIFF_MODE        759

//Note: All actions are preformed only if they exist for the character.

// High tag = seconds
#define TRACK_ACTOR_STAND           770
// High tag = height value (default 384)
#define TRACK_ACTOR_JUMP            771
// Toggle crawl state
#define TRACK_ACTOR_CRAWL           772
// Toggle swim state
#define TRACK_ACTOR_SWIM            773
// Toggle fly spell
#define TRACK_ACTOR_FLY             774
// High tag = seconds
#define TRACK_ACTOR_SIT             776
// High tag = seconds
#define TRACK_ACTOR_DEATH1          777
// High tag = seconds
#define TRACK_ACTOR_DEATH2          778
// Air Death!
// High tag = seconds
#define TRACK_ACTOR_DEATH_JUMP      779

// Close range attacks - in order of least powerful to most
// High tag = seconds
#define TRACK_ACTOR_CLOSE_ATTACK1   780
#define TRACK_ACTOR_CLOSE_ATTACK2   781
// Long range attacks - in order of least powerful to most
// High tag = seconds
#define TRACK_ACTOR_ATTACK1         782
#define TRACK_ACTOR_ATTACK2         783
#define TRACK_ACTOR_ATTACK3         784
#define TRACK_ACTOR_ATTACK4         785
#define TRACK_ACTOR_ATTACK5         786
#define TRACK_ACTOR_ATTACK6         787

// High tag = seconds
#define TRACK_ACTOR_LOOK            790
// High tag = seconds to pause
// Point of the sprite angle in the direction of the operatable sector/wall/switch
// Actor presses the space bar to operate sector/wall/switch.
#define TRACK_ACTOR_OPERATE         791
// High tag = height to go up before jumping to next point
// Sprite angle must be facing the ladder
#define TRACK_ACTOR_CLIMB_LADDER    792
// Set up a default jump value - for use before climbing ladders etc
#define TRACK_ACTOR_SET_JUMP        793

// Specail Action - depends on each actor
// High tag = seconds
#define TRACK_ACTOR_SPECIAL1        795
#define TRACK_ACTOR_SPECIAL2        796

// Jump if moving forward on track
#define TRACK_ACTOR_JUMP_IF_FORWARD 797
// Jump if moving backward on track
#define TRACK_ACTOR_JUMP_IF_REVERSE 798

// Wait for player to come into range before moving from this point.
// High tag = Distance from player at which NPC can start moving.
#define TRACK_ACTOR_WAIT_FOR_PLAYER 799

// Wait for trigger to be tripped before moving from this point.
// Use TAG_TRIGGER_ACTORS defined above is used to trigger the actor.
#define TRACK_ACTOR_WAIT_FOR_TRIGGER 800

// Quick TAGS - Used internally by ME ONLY
#define TRACK_ACTOR_QUICK_JUMP       801
#define TRACK_ACTOR_QUICK_JUMP_DOWN  802
#define TRACK_ACTOR_QUICK_SUPER_JUMP 803
#define TRACK_ACTOR_QUICK_SCAN       804
#define TRACK_ACTOR_QUICK_EXIT       805
#define TRACK_ACTOR_QUICK_LADDER     806
#define TRACK_ACTOR_QUICK_OPERATE    807
#define TRACK_ACTOR_QUICK_DUCK       808
#define TRACK_ACTOR_QUICK_DEFEND     809

//////////////////////////////////////////////////////////////////////////////////////////
//
// SPRITE TAGS
//
//////////////////////////////////////////////////////////////////////////////////////////

// 100-199 are reserved for placing actors on tracks
#define TAG_ACTOR_TRACK_BEGIN       30000
#define TAG_ACTOR_TRACK_END         30099

// When "operated" moves grating in the direction the sprite is pointing
// High tag = distance to move the grate - 1024 is a good distance
#define TAG_SPRITE_GRATING          200

// Place an actor with this tag and it will not spawn until it is triggered.
// High tag = Match number
#define TAG_SPAWN_ACTOR  203
#define TAG_SPRITE_HIT_MATCH  257

//////////////////////////////////////////////////////////////////////////////////////////
//
// WALL TAGS
//
//////////////////////////////////////////////////////////////////////////////////////////

// Sine wave wall effect - max 5 per level
//
// EXP - Tag the first wall with 300, last with 302.
//       Use point2 to see which direction the wall goes.
//
// 1st Sector High Tag = range
// 2nd Sector High Tag = speed
// 3th Sector High Tag = a distance from one peak (top of curve) to the next

// Sine Wave wall in y direction
#define TAG_WALL_SINE_Y_BEGIN 300
// Sine Wave wall in x direction
#define TAG_WALL_SINE_X_BEGIN 301
#define TAG_WALL_SINE_Y_END 302
#define TAG_WALL_SINE_X_END 303

// Switch to rotate a SO 90 degrees when pressed.
// High tag = SO number to rotate.
#define TAG_ROTATE_SO_SWITCH 304

// Climbable wall that has a top.
#define TAG_WALL_CLIMB 305

// Smashable walls
// High Tag is SPAWN_SPOT match tag
#define TAG_WALL_BREAK       307

// For SO's that rotate - tag ONE wall of the loop to make loop NOT rotate with the rest of the
// SO.  Does not matter if you tag the inside or outside wall.
// Exp - drill bit
#define TAG_WALL_LOOP_DONT_SPIN 500
// Reverse spin for this wall loop and sector.  Tag same as DONT_SPIN.
// Exp - pit with teath
#define TAG_WALL_LOOP_REVERSE_SPIN 501
// Spin twice as fast as SO.  Tag same as DONT_SPIN.
// Exp - whirlpool
#define TAG_WALL_LOOP_SPIN_2X 502
// Spin 4X as fast as SO.  Tag same as DONT_SPIN.
// Exp - whirlpool
#define TAG_WALL_LOOP_SPIN_4X 503
// Tag the outer loop of a SO with this.
#define TAG_WALL_LOOP_OUTER 504
// Just tag one wall so it does not move.  My attempt to fix sector splitting for the
// SO outer loop.  Not working real well.
#define TAG_WALL_DONT_MOVE 505

// Just tag one wall of closed loop teleporter.
// High byte is speed - shift value 0-6
#define TAG_WALL_LOOP_TELEPORTER_PAN 506

// Just tag one wall in loop so it does not scale.
#define TAG_WALL_LOOP_DONT_SCALE 507

// Tag the secondary outer loop of a SO with this.  Use with Rectangle Clipping
// and Stacked sectors.
#define TAG_WALL_LOOP_OUTER_SECONDARY 508

#define TAG_WALL_ALIGN_SLOPE_TO_POINT    550
#endif


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 1997, 2005 - 3D Realms Entertainment

This file is part of Shadow Warrior version 1.2

Shadow Warrior is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

Original Source: 1997 - Frank Maddin and Jim Norwood
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------
#undef MAIN
#include "build.h"

#include "keys.h"
#include "names2.h"
#include "panel.h"
#include "lists.h"
#include "game.h"
#include "common_game.h"
#include "pal.h"
#include "text.h"
#include "menus.h"

#include "network.h"

#define PANEL_FONT_G 3636
#define PANEL_FONT_Y 3646
#define PANEL_FONT_R 3656

#define PANEL_SM_FONT_G 3601
#define PANEL_SM_FONT_Y 3613
#define PANEL_SM_FONT_R 3625

const char *KeyDoorMessage[MAX_KEYS] =
{
    "You need a RED key for this door.",
    "You need a BLUE key for this door.",
    "You need a GREEN key for this door.",
    "You need a YELLOW key for this door.",
    "You need a GOLD key for this door.",
    "You need a SILVER key for this door.",
    "You need a BRONZE key for this door.",
    "You need a RED key for this door."
};

void
DisplaySummaryString(PLAYERp pp, short xs, short ys, short color, short shade, const char *buffer)
{
    short size,x;
    const char *ptr;
    char ch;
    PANEL_SPRITEp nsp;
    short font_pic;
    static short font_base[] = {PANEL_SM_FONT_G, PANEL_SM_FONT_Y, PANEL_SM_FONT_R};

    for (ptr = buffer, x = xs; *ptr; ptr++, x += size)
    {
        ch = *ptr;
        if (ch == ' ')
        {
            size = 4;
            continue;
        }

        switch (ch)
        {
        case '\\':
            ch = '0' - 1; // one pic before 0
            break;
        case ':':
            ch = '9' + 1; // one pic after nine
            break;
        }

        ASSERT(color < 3);
        font_pic = font_base[color] + (ch - '0');
        nsp = pSpawnFullScreenSprite(pp, font_pic, PRI_FRONT_MAX, x, ys);
        nsp->shade = shade;
        size = tilesiz[font_pic].x + 1;
    }
}

PANEL_SPRITEp
pClearTextLineID(PLAYERp pp, short id, long y, short pri)
{
    PANEL_SPRITEp psp=NULL, next;

    TRAVERSE(&pp->PanelSpriteList, psp, next)
    {
        // early out
        if (psp->priority > pri)
            return NULL;

        if (psp->ID == id && psp->y == y && psp->priority == pri)
        {
            SetRedrawScreen(psp->PlayerP);
            //SET(psp->flags, PANF_INVISIBLE);
            pSetSuicide(psp);
        }
    }

    return NULL;
}

// only call this from menu code - it does a pKillSprite
PANEL_SPRITEp
pMenuClearTextLineID(PLAYERp pp, short id, long y, short pri)
{
    PANEL_SPRITEp psp=NULL, next;

    TRAVERSE(&pp->PanelSpriteList, psp, next)
    {
        // early out
        if (psp->priority > pri)
            return NULL;

        if (psp->ID == id && psp->y == y && psp->priority == pri)
        {
            SetRedrawScreen(psp->PlayerP);
            pKillSprite(psp);
            //pSetSuicide(psp);
        }
    }

    return NULL;
}

void
pClearTextLine(PLAYERp pp, long y)
{
    SetRedrawScreen(pp);
    pClearTextLineID(pp, ID_TEXT, y, PRI_FRONT_MAX);
}

void
StringTimer(PANEL_SPRITEp psp)
{
    if ((psp->kill_tics -= synctics) <= 0)
    {
        SetRedrawScreen(psp->PlayerP);
        //pSetSuicide(psp);  // did not work here
        pKillSprite(psp);
        return;
    }
}

void
PutStringTimer(PLAYERp pp, short x, short y, const char *string, short seconds)
{
    int ndx, offset;
    char c;
    PANEL_SPRITEp nsp;
    long kill_tics;
    short id, ac;
    PANEL_SPRITE_FUNCp func;

    offset = x;

    if (seconds == 999)
    {
        pClearTextLineID(pp, ID_TEXT, y, PRI_FRONT_MAX);
        func = NULL;
        kill_tics = 0;
        id = ID_TEXT;
    }
    else
    {
        pClearTextLineID(pp, ID_TEXT, y, PRI_FRONT_MAX);
        func = StringTimer;
        kill_tics = seconds * 120;
        id = ID_TEXT;
    }

    for (ndx = 0; (c = string[ndx]) != 0; ndx++)
    {
        ac = c - '!' + STARTALPHANUM;
        if ((ac < STARTALPHANUM || ac > ENDALPHANUM)  && c != asc_Space)
            break;

        if (c > asc_Space && c < 127)
        {
            nsp = pSpawnFullViewSprite(pp, ac, PRI_FRONT_MAX, offset, y);
            nsp->PanelSpriteFunc = func;
            nsp->kill_tics = kill_tics;
            nsp->ID = id;
            offset += tilesiz[ac].x;
        }
        else if (c == asc_Space)
            offset += 4;                // Special case for space char
    }
}

void
KillString(PLAYERp pp, short y)
{
    pClearTextLineID(pp, ID_TEXT, y, PRI_FRONT_MAX);
}

PANEL_SPRITEp
pClearSpriteXY(PLAYERp pp, short x, short y)
{
    PANEL_SPRITEp psp=NULL, next;

    TRAVERSE(&pp->PanelSpriteList, psp, next)
    {
        if (psp->x == x && psp->y == y)
            pSetSuicide(psp);
    }

    return NULL;
}

PANEL_SPRITEp
pClearSpriteID(PLAYERp pp, short id)
{
    PANEL_SPRITEp psp=NULL, next;

    TRAVERSE(&pp->PanelSpriteList, psp, next)
    {
        if (psp->ID == id)
            pSetSuicide(psp);
    }

    return NULL;
}

void
DisplayPanelNumber(PLAYERp pp, short xs, short ys, int number)
{
    char buffer[32];
    char *ptr;
    short x, size;

    sprintf(buffer, "%03d", number);

    for (ptr = buffer, x = xs; *ptr; ptr++, x += size)
    {
        if (!isdigit(*ptr))
        {
            size = 0;
            continue;
        }

        pSpawnFullScreenSprite(pp, PANEL_FONT_G + (*ptr - '0'), PRI_FRONT_MAX, x, ys);

        size = tilesiz[PANEL_FONT_G + (*ptr - '0')].x + 1;
    }
}

void
DisplayMiniBarNumber(short xs, short ys, int number)
{
    char buffer[32];
    char *ptr;
    short x, size;
    short pic;

    sprintf(buffer, "%03d", number);

    for (ptr = buffer, x = xs; *ptr; ptr++, x += size)
    {
        if (!isdigit(*ptr))
        {
            size = 0;
            continue;
        }

        pic = PANEL_FONT_G + (*ptr - '0');

        rotatesprite((long)x << 16, (long)ys << 16, (1 << 16), 0,
                     pic, 0, 0,
                     ROTATE_SPRITE_SCREEN_CLIP | ROTATE_SPRITE_CORNER | RS_ALIGN_L,
                     0, 0, xdim - 1, ydim - 1);

        size = tilesiz[PANEL_FONT_G + (*ptr - '0')].x + 1;
    }
}

void
DisplayMiniBarSmString(PLAYERp UNUSED(pp), short xs, short ys, short pal, const char *buffer)
{
    short size=4,x;
    const char *ptr;
    short pic;

#define FRAG_FIRST_ASCII ('!') //exclamation point
#define FRAG_FIRST_TILE 2930 //exclamation point

    for (ptr = buffer, x = xs; *ptr; ptr++, x += size)
    {
        if (*ptr == ' ')
            continue;

        ASSERT(*ptr >= '!' && *ptr <= '}');

        pic = FRAG_FIRST_TILE + (*ptr - FRAG_FIRST_ASCII);

        rotatesprite((long)x << 16, (long)ys << 16, (1 << 16), 0,
                     pic, 0, pal,
                     ROTATE_SPRITE_SCREEN_CLIP | ROTATE_SPRITE_CORNER | RS_ALIGN_L,
                     0, 0, xdim - 1, ydim - 1);
    }
}

void
DisplaySmString(PLAYERp pp, short xs, short ys, short pal, const char *buffer)
{
    short size=4,x;
    const char *ptr;
    PANEL_SPRITEp nsp;
    // ID is base + (0-3)
    //short id = ID_TEXT + MOD4(pp->pnum);

#define FRAG_FIRST_ASCII ('!') //exclamation point
#define FRAG_FIRST_TILE 2930 //exclamation point

    for (ptr = buffer, x = xs; *ptr; ptr++, x += size)
    {
        if (*ptr == ' ')
            continue;

        ASSERT(*ptr >= '!' && *ptr <= '}');

        nsp = pSpawnFullScreenSprite(pp, FRAG_FIRST_TILE + (*ptr - FRAG_FIRST_ASCII), PRI_FRONT_MAX, x, ys);
        nsp->pal = pal;
        //nsp->ID = id;
    }
}

void
DisplayFragString(PLAYERp pp, short xs, short ys, const char *buffer)
{
    short size=4,x;
    const char *ptr;
    PANEL_SPRITEp nsp;
    // ID is base + (0-3)
    short id = ID_TEXT + MOD4(pp->pnum);

    PLAYERp my_pp = Player + myconnectindex;

#define FRAG_FIRST_ASCII ('!') //exclamation point
#define FRAG_FIRST_TILE 2930 //exclamation point

    //pClearTextLineID(my_pp, id, ys, PRI_FRONT_MAX);

    for (ptr = buffer, x = xs; *ptr; ptr++, x += size)
    {
        if (*ptr == ' ')
            continue;

        ASSERT(*ptr >= '!' && *ptr <= '}');

        nsp = pSpawnFullScreenSprite(my_pp, FRAG_FIRST_TILE + (*ptr - FRAG_FIRST_ASCII), PRI_FRONT_MAX, x, ys);
        nsp->ID = id;
        //nsp->pal = PALETTE_PLAYER0 + pp->TeamColor;
        //if (pp->SpriteP)
        nsp->pal = User[pp->SpriteP - sprite]->spal;
    }
}

void
DisplayFragNumbers(PLAYERp pp)
{
    char buffer[32];
    short xs, ys;
    short frag_bar;
    short pnum = pp - Player;

    static int xoffs[] =
    {
        69, 147, 225, 303
    };

    PLAYERp my_pp = Player + myconnectindex;

    // black tile to erase frag count
#define FRAG_ERASE_NAME 2375
#define FRAG_ERASE_NUMBER 2376
#define FRAG_YOFF 2

    //xs = FRAG_XOFF;
    ys = FRAG_YOFF;

    // frag bar 0 or 1
    frag_bar = ((pnum)/4);
    // move y down according to frag bar number
    ys = ys + (tilesiz[FRAG_BAR].y-2) * frag_bar;

    // move x over according to the number of players
    xs = xoffs[MOD4(pnum)];

    sprintf(buffer, "%03d", pp->Kills);

    // erase old kill count
    pSpawnFullScreenSprite(my_pp, FRAG_ERASE_NUMBER, PRI_MID+1, xs-1, ys);

    DisplayFragString(pp, xs, ys, buffer);
}

void
DisplayFragNames(PLAYERp pp)
{
    short xs, ys;
    short frag_bar;
    short pnum = pp - Player;

    static int xoffs[] =
    {
        7, 85, 163, 241
    };

    PLAYERp my_pp = Player + myconnectindex;

    //xs = FRAG_XOFF;
    ys = FRAG_YOFF;

    // frag bar 0 or 1
    frag_bar = ((pnum)/4);
    // move y down according to frag bar number
    ys = ys + (tilesiz[FRAG_BAR].y-2) * frag_bar;

    // move x over according to the number of players
    xs = xoffs[MOD4(pnum)];

    // erase old kill count
    pSpawnFullScreenSprite(my_pp, FRAG_ERASE_NAME, PRI_MID+1, xs-1, ys);

    DisplayFragString(pp, xs, ys, pp->PlayerName);
}

short GlobInfoStringTime = TEXT_INFO_TIME;
void PutStringInfo(PLAYERp pp, const char *string)
{
    if (pp-Player != myconnectindex)
        return;

    if (!gs.Messages)
        return;

    CON_ConMessage("%s", string); // Put it in the console too
    PutStringInfoLine(pp, string);
}

void PutStringInfoLine(PLAYERp pp, const char *string)
{
    short x,y;
    short w,h;

    if (pp-Player != myconnectindex)
        return;

    MNU_MeasureString(string, &w, &h);

    x = TEXT_XCENTER(w);
    y = TEXT_INFO_LINE(0);

    // Move lower on this level because of boss meters
    //if ((Level == 20 && numplayers > 1) || numplayers > 4)
    //    y += 20;
    //if (numplayers > 1 && numplayers <= 4)
    //    y+= 10;

    PutStringTimer(pp, x, y, string, GlobInfoStringTime);
    // when printing info line clear the second line
    //PutStringInfoLine2(pp, "");
}

void PutStringInfoLine2(PLAYERp pp, const char *string)
{
    short x,y;
    short w,h;

    if (pp-Player != myconnectindex)
        return;

    MNU_MeasureString(string, &w, &h);

    x = TEXT_XCENTER(w);
    y = TEXT_INFO_LINE(1);

    PutStringTimer(pp, x, y, string, GlobInfoStringTime);
}

void
pMenuClearTextLine(PLAYERp pp)
{
    pMenuClearTextLineID(pp, ID_TEXT, TEXT_INFO_LINE(0), PRI_FRONT_MAX);
    pMenuClearTextLineID(pp, ID_TEXT, TEXT_INFO_LINE(1), PRI_FRONT_MAX);
}

#define TEXT_PLAYER_INFO_TIME (3)
#define TEXT_PLAYER_INFO_Y (200 - 40)

void PutStringPlayerInfo(PLAYERp pp, const char *string)
{
    short x,y;
    short w,h;

    if (pp-Player != myconnectindex)
        return;

    if (!gs.Messages)
        return;

    MNU_MeasureString(string, &w, &h);

    x = TEXT_XCENTER(w);
    y = TEXT_PLAYER_INFO_Y;

    PutStringTimer(pp, x, y, string, GlobInfoStringTime);
}


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 1997, 2005 - 3D Realms Entertainment

This file is part of Shadow Warrior version 1.2

Shadow Warrior is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

Original Source: 1997 - Frank Maddin and Jim Norwood
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------

#define TEXT_INFO_TIME (3)
#define TEXT_INFO_X (16)
//#define TEXT_INFO_Y (20)
#define TEXT_INFO_Y (40)
#define TEXT_INFO_YOFF (10)
#define TEXT_INFO_LINE(line) (TEXT_INFO_Y + ((line) * TEXT_INFO_YOFF))
//#define TEXT_INFO_LINE(line) (TEXT_INFO_Y + ((line) * TEXT_INFO_YOFF) + GlobalInfoLineOffset)

void DisplayFragNames(PLAYERp pp);
void DisplayMiniBarSmString(PLAYERp pp,short xs,short ys, short pal, const char *buffer);
void DisplaySmString(PLAYERp pp, short xs, short ys, short pal, const char *buffer);
void DisplayMiniBarNumber(short xs,short ys,int number);
void DisplaySummaryString(PLAYERp pp,short xs,short ys,short color,short shade,const char *buffer);
void DisplayPanelNumber(PLAYERp pp,short xs,short ys,int number);
void PutStringInfo(PLAYERp pp, const char *string);
void PutStringInfoLine(PLAYERp pp, const char *string);
void PutStringInfoLine2(PLAYERp pp, const char *string);
void pClearTextLine(PLAYERp pp,long y);
void pMenuClearTextLine(PLAYERp pp);

void StringTimer(PANEL_SPRITEp psp);