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 "names2.h"
#include "game.h"
#include "light.h"

/* #define LIGHT_Match(sp)         (SP_TAG2((sp)))                      */
/* #define LIGHT_Type(sp)          (SP_TAG3((sp)))                      */
/* #define LIGHT_MaxTics(sp)       (SP_TAG4((sp)))                      */
/* #define LIGHT_MaxBright(sp)     (SP_TAG5((sp)))                      */
/* #define LIGHT_MaxDark(sp)       (SP_TAG6((sp)))                      */
/* #define LIGHT_ShadeInc(sp)      (SP_TAG7((sp)))                      */
/*                                                                      */
/* #define LIGHT_Dir(sp)           (!!(TEST((sp)->extra, SPRX_BOOL10))) */
/* #define LIGHT_DirChange(sp)     (FLIP((sp)->extra, SPRX_BOOL10))     */
/*                                                                      */
/* #define LIGHT_Shade(sp)         ((sp)->shade)                        */
/* #define LIGHT_FloorShade(sp)    ((sp)->xoffset)                      */
/* #define LIGHT_CeilingShade(sp)  ((sp)->yoffset)                      */
/* #define LIGHT_Tics(sp)          ((sp)->z)                            */
/*                                                                      */
/* #define LIGHT_DiffuseNum(sp) (SP_TAG3((sp)))                         */
/* #define LIGHT_DiffuseMult(sp) (SP_TAG4((sp)))                        */

void SectorLightShade(SPRITEp sp, short intensity)
{
    short w, startwall, endwall;
    int8_t* wall_shade;
    short base_shade;
    short wallcount;

    if (TEST_BOOL8(sp))
        intensity = -intensity;

    if (!TEST_BOOL2(sp))
    {
        if (!TEST_BOOL6(sp))
            sector[sp->sectnum].floorpal = sp->pal;
        sector[sp->sectnum].floorshade = LIGHT_FloorShade(sp) + intensity;     // floor change
    }

    if (!TEST_BOOL3(sp))
    {
        if (!TEST_BOOL6(sp))
            sector[sp->sectnum].ceilingpal = sp->pal;
        sector[sp->sectnum].ceilingshade = LIGHT_CeilingShade(sp) + intensity;   // ceiling change
    }

    // change wall
    if (!TEST_BOOL4(sp))
    {
        ASSERT(User[sp - sprite] && User[sp - sprite]->WallShade);
        wall_shade = User[sp - sprite]->WallShade;

        startwall = sector[sp->sectnum].wallptr;
        endwall = startwall + sector[sp->sectnum].wallnum - 1;

        for (w = startwall, wallcount = 0; w <= endwall; w++)
        {
            base_shade = wall_shade[wallcount];
            wall[w].shade = base_shade + intensity;
            if (!TEST_BOOL6(sp))
                wall[w].pal = sp->pal;
            wallcount++;

            if (TEST(sp->extra, SPRX_BOOL5))
            {
                uint16_t const nextwall = wall[w].nextwall;
                if (nextwall < MAXWALLS)
                {
                    base_shade = wall_shade[wallcount];
                    wall[nextwall].shade = base_shade + intensity;
                    if (!TEST_BOOL6(sp))
                        wall[nextwall].pal = sp->pal;
                    wallcount++;
                }
            }
        }
    }
}

void DiffuseLighting(SPRITEp sp)
{
    short i, nexti;
    short count;
    short shade;
    SPRITEp dsp;

    // diffused lighting
    count = 0;
    TRAVERSE_SPRITE_STAT(headspritestat[STAT_LIGHTING_DIFFUSE],i,nexti)
    {
        dsp = &sprite[i];

        // make sure matchs match
        if (LIGHT_Match(dsp) != LIGHT_Match(sp))
            continue;

        shade = sp->shade + ((LIGHT_DiffuseNum(dsp) + 1) * LIGHT_DiffuseMult(dsp));

        if (shade > LIGHT_MaxDark(sp))
            shade = LIGHT_MaxDark(sp);

        if (!TEST_BOOL6(dsp))
            dsp->pal = sp->pal;

        SectorLightShade(dsp, shade);

        count++;
    }
}

void DoLightingMatch(short match, short state)
{
    short i,nexti;
    SPRITEp sp;

    TRAVERSE_SPRITE_STAT(headspritestat[STAT_LIGHTING],i,nexti)
    {
        sp = &sprite[i];

        if (LIGHT_Match(sp) != match)
            continue;

        switch (LIGHT_Type(sp))
        {
        case LIGHT_CONSTANT:

            // initialized
            SET_BOOL9(sp);

            // toggle
            if (state == -1)
                state = !TEST_BOOL1(sp);

            if (state == ON)
            {
                SET_BOOL1(sp);
                sp->shade = -LIGHT_MaxBright(sp);
                sp->pal = User[sp-sprite]->spal; // on
                SectorLightShade(sp, sp->shade);
                DiffuseLighting(sp);
            }
            else
            {
                RESET_BOOL1(sp);
                sp->shade = LIGHT_MaxDark(sp);
                sp->pal = 0; // off
                SectorLightShade(sp, sp->shade);
                DiffuseLighting(sp);
            }
            break;

        case LIGHT_FLICKER:
        case LIGHT_FADE:
            // initialized
            SET_BOOL9(sp);

            // toggle
            if (state == -1)
                state = !TEST_BOOL1(sp);

            if (state == ON)
            {
                // allow fade or flicker
                SET_BOOL1(sp);
            }
            else
            {
                RESET_BOOL1(sp);
                sp->shade = LIGHT_MaxDark(sp);
                SectorLightShade(sp, sp->shade);
                DiffuseLighting(sp);
            }
            break;

        case LIGHT_FADE_TO_ON_OFF:

            // initialized
            SET_BOOL9(sp);

            // toggle
            //if (state == -1)
            //    state = !TEST_BOOL1(sp);

            if (state == ON)
            {
                if (LIGHT_Dir(sp) == 1)
                {
                    LIGHT_DirChange(sp);
                }
            }
            else if (state == OFF)
            {
                if (LIGHT_Dir(sp) == 0)
                {
                    LIGHT_DirChange(sp);
                }
            }

            // allow fade or flicker
            SET_BOOL1(sp);
            break;

        case LIGHT_FLICKER_ON:

            // initialized
            SET_BOOL9(sp);

            // toggle
            if (state == -1)
                state = !TEST_BOOL1(sp);

            if (state == ON)
            {
                // allow fade or flicker
                SET_BOOL1(sp);
            }
            else
            {
                // turn it off till next switch
                short spal = sp->pal;
                RESET_BOOL1(sp);
                sp->pal = 0;
                sp->shade = LIGHT_MaxDark(sp);
                SectorLightShade(sp, sp->shade);
                DiffuseLighting(sp);
                sp->pal = spal;
            }
            break;
        }
    }
}

void InitLighting(void)
{
    short i,nexti;
    SPRITEp sp;

    // processed on level startup
    // puts lights in correct state
    TRAVERSE_SPRITE_STAT(headspritestat[STAT_LIGHTING],i,nexti)
    {
        sp = &sprite[i];

        if (!TEST_BOOL9(sp))
        {
            DoLightingMatch(LIGHT_Match(sp), !!TEST_BOOL1(sp));
        }
    }
}

void DoLighting(void)
{
    short i,nexti;
    SPRITEp sp;

    TRAVERSE_SPRITE_STAT(headspritestat[STAT_LIGHTING],i,nexti)
    {
        sp = &sprite[i];

        // on/off test
        if (TEST_BOOL1(sp) == OFF)
            continue;

        switch (LIGHT_Type(sp))
        {
        case LIGHT_CONSTANT:
            break;

        case LIGHT_FLICKER:

            LIGHT_Tics(sp) += synctics;
            while (LIGHT_Tics(sp) >= LIGHT_MaxTics(sp))
            {
                LIGHT_Tics(sp) -= LIGHT_MaxTics(sp);

                if ((RANDOM_P2(128 << 8) >> 8) > 64)
                {
                    sp->shade = -LIGHT_MaxBright(sp) + RANDOM_RANGE(LIGHT_MaxBright(sp) + LIGHT_MaxDark(sp));
                    SectorLightShade(sp, sp->shade);
                    DiffuseLighting(sp);
                }
                else
                {
                    // turn off lighting - even colored lighting
                    short spal = sp->pal;
                    sp->pal = 0;
                    sp->shade = LIGHT_MaxDark(sp);
                    SectorLightShade(sp, sp->shade);
                    DiffuseLighting(sp);
                    sp->pal = spal;
                }
            }

            break;

        case LIGHT_FADE:

            LIGHT_Tics(sp) += synctics;

            while (LIGHT_Tics(sp) >= LIGHT_MaxTics(sp))
            {
                LIGHT_Tics(sp) -= LIGHT_MaxTics(sp);

                if (LIGHT_Dir(sp) == 1)
                {
                    sp->shade += LIGHT_ShadeInc(sp);
                    if (sp->shade >= LIGHT_MaxDark(sp))
                        LIGHT_DirChange(sp);
                }
                else
                {
                    sp->shade -= LIGHT_ShadeInc(sp);
                    if (sp->shade <= -LIGHT_MaxBright(sp))
                        LIGHT_DirChange(sp);
                }

                SectorLightShade(sp, sp->shade);
                DiffuseLighting(sp);
            }

            break;

        case LIGHT_FADE_TO_ON_OFF:

            LIGHT_Tics(sp) += synctics;

            while (LIGHT_Tics(sp) >= LIGHT_MaxTics(sp))
            {
                LIGHT_Tics(sp) -= LIGHT_MaxTics(sp);

                if (LIGHT_Dir(sp) == 1)
                {
                    sp->shade += LIGHT_ShadeInc(sp);
                    if (sp->shade >= LIGHT_MaxDark(sp))
                    {
                        sp->pal = 0; // off
                        LIGHT_DirChange(sp);
                        // stop it until switch is hit
                        RESET_BOOL1(sp);
                    }
                }
                else
                {
                    sp->shade -= LIGHT_ShadeInc(sp);
                    sp->pal = User[sp-sprite]->spal; // on
                    if (sp->shade <= -LIGHT_MaxBright(sp))
                    {
                        LIGHT_DirChange(sp);
                        // stop it until switch is hit
                        RESET_BOOL1(sp);
                    }
                }

                SectorLightShade(sp, sp->shade);
                DiffuseLighting(sp);
            }

            break;

        case LIGHT_FLICKER_ON:

            LIGHT_Tics(sp) += synctics;

            while (LIGHT_Tics(sp) >= LIGHT_MaxTics(sp))
            {
                LIGHT_Tics(sp) -= LIGHT_MaxTics(sp);

                if ((RANDOM_P2(128 << 8) >> 8) > 64)
                {
                    sp->shade = -LIGHT_MaxBright(sp) + RANDOM_RANGE(LIGHT_MaxBright(sp) + LIGHT_MaxDark(sp));
                    SectorLightShade(sp, sp->shade);
                    DiffuseLighting(sp);
                }
                else
                {
                    // turn off lighting - even colored lighting
                    short spal = sp->pal;
                    sp->pal = 0;
                    sp->shade = LIGHT_MaxDark(sp);
                    SectorLightShade(sp, sp->shade);
                    DiffuseLighting(sp);
                    sp->pal = spal;
                }

                if ((RANDOM_P2(128 << 8) >> 8) < 8)
                {
                    // set to full brightness
                    sp->shade = -LIGHT_MaxBright(sp);
                    SectorLightShade(sp, sp->shade);
                    DiffuseLighting(sp);
                    // turn it off until a swith happens
                    RESET_BOOL1(sp);
                }
            }
            break;
        }
    }
}


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
*/
//-------------------------------------------------------------------------

void SectorLightShade(SPRITEp sp, short intensity);
void DiffuseLighting(SPRITEp sp);
void DoLightingMatch(short match, short state);
void InitLighting(void);
void DoLighting(void);

// Descriptive Light variables mapped from other variables

#define LIGHT_Match(sp)         (SP_TAG2((sp)))
#define LIGHT_Type(sp)          (SP_TAG3((sp)))
#define LIGHT_MaxTics(sp)       (SP_TAG4((sp)))
#define LIGHT_MaxBright(sp)     (SP_TAG5((sp)))
#define LIGHT_MaxDark(sp)       (SP_TAG6((sp)))
#define LIGHT_ShadeInc(sp)      (SP_TAG7((sp)))

#define LIGHT_Dir(sp)           (!!(TEST((sp)->extra, SPRX_BOOL10)))
#define LIGHT_DirChange(sp)     (FLIP((sp)->extra, SPRX_BOOL10))

#define LIGHT_Shade(sp)         ((sp)->shade)
#define LIGHT_FloorShade(sp)    ((sp)->xoffset)
#define LIGHT_CeilingShade(sp)  ((sp)->yoffset)
#define LIGHT_Tics(sp)          ((sp)->z)

#define LIGHT_DiffuseNum(sp) (SP_TAG3((sp)))
#define LIGHT_DiffuseMult(sp) (SP_TAG4((sp)))

enum LightTypes {LIGHT_CONSTANT, LIGHT_FLICKER, LIGHT_FADE, LIGHT_FLICKER_ON, LIGHT_FADE_TO_ON_OFF};

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 LISTS_H

#define LISTS_H

/********************************************************************/

typedef
    struct List
{
    struct List *Next;
    struct List *Prev;
} LISTHEAD, *LIST;

#define FIRST(list)        (list->Next)
#define LAST(list)         (list->Prev)

#define INITLIST(list)          ( ((LIST) list)->Prev = ((LIST) list)->Next = (LIST) list)

#define INSERT(list, nodep)  ( ((LIST) nodep)->Prev = (LIST) list,         \
                               ((LIST) nodep)->Next = ((LIST) list)->Next, \
                               ((LIST)  list)->Next = (LIST) nodep,        \
                               ((LIST) nodep)->Next->Prev = (LIST) nodep)

#define INSERT_TAIL(list, nodep)  ( ((LIST) nodep)->Next = (LIST) list,  \
                                    ((LIST) nodep)->Prev = ((LIST) list)->Prev, \
                                    ((LIST)  list)->Prev = (LIST) nodep,        \
                                    ((LIST) nodep)->Prev->Next = (LIST) nodep)

#define REMOVE(nodep)        ( ((LIST) nodep)->Prev->Next = ((LIST) nodep)->Next, \
                               ((LIST) nodep)->Next->Prev = ((LIST) nodep)->Prev)

#define TRAVERSE(l, o, n)    ASSERT(((LIST)l)->Next && ((LIST)l)->Prev); for (o = (decltype(o))(((LIST)l)->Next);      \
                                                                              n = o->Next, (LIST) o != (LIST) l; \
                                                                              o = n)

#define EMPTY(list)          (((LIST) list)->Next == (LIST) list)

#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
*/
//-------------------------------------------------------------------------
#include "build.h"
#include "common.h"

#include "mytypes.h"
#include "keys.h"
#include "names2.h"
#include "panel.h"
#include "game.h"
#include "tags.h"
#include "player.h"
#include "mclip.h"

#if 0
int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
    int i;
    int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
    SPRITEp sp = pp->sop->sp_child;
    USERp u = User[sp - sprite];
    SECTOR_OBJECTp sop = pp->sop;
    short ang;
    short min_ndx;
    int min_dist = 999999;
    int dist;

    int ret_start;
    int ret[MAX_CLIPBOX];
    int x[MAX_CLIPBOX],y[MAX_CLIPBOX];

    for (i = 0; i < sop->clipbox_num; i++)
    {
        ang = NORM_ANGLE(fix16_to_int(pp->q16ang) + sop->clipbox_ang[i]);
        ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
        oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);

        // move the box
        ret[i] = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);

        // save the dist moved
        dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);

        if (dist < min_dist)
        {
            min_dist = dist;
            min_ndx = i;
        }
    }

    // put posx and y off from offset
    pp->posx -= ox[min_ndx] - x[min_ndx];
    pp->posy -= oy[min_ndx] - y[min_ndx];

    return ret[min_ndx];
}
#endif

#if 0
int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
    int i;
    int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
    SPRITEp sp = pp->sop->sp_child;
    USERp u = User[sp - sprite];
    SECTOR_OBJECTp sop = pp->sop;
    short ang;
    short min_ndx;
    int min_dist = 999999;
    int dist;

    int ret_start;
    int ret[MAX_CLIPBOX];
    int x[MAX_CLIPBOX],y[MAX_CLIPBOX];

    for (i = 0; i < sop->clipbox_num; i++)
    {
        ang = NORM_ANGLE(fix16_to_int(pp->q16ang) + sop->clipbox_ang[i]);
        ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
        oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);

        // move the box
        //pushmove_old(&x[i], &y[i], &z, &pp->cursectnum, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
        ret[i] = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
        //pushmove_old(&x[i], &y[i], &z, &pp->cursectnum, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);

        // save the dist moved
        dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);

        if (dist < min_dist)
        {
            min_dist = dist;
            min_ndx = i;
        }
    }

    // put posx and y off from offset
    pp->posx -= ox[min_ndx] - x[min_ndx];
    pp->posy -= oy[min_ndx] - y[min_ndx];

    return ret[min_ndx];
}
#endif

#if 0
int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
    int i;
    int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
    SPRITEp sp = pp->sop->sp_child;
    USERp u = User[sp - sprite];
    SECTOR_OBJECTp sop = pp->sop;
    short ang;
    short min_ndx;
    int min_dist = 999999;
    int dist;

    int ret_start;
    int ret[MAX_CLIPBOX];
    int x[MAX_CLIPBOX],y[MAX_CLIPBOX];

    int xvect,yvect;
    int xs,ys;

    for (i = 0; i < sop->clipbox_num; i++)
    {
        // move the box to position instead of using offset- this prevents small rounding errors
        // allowing you to move through wall
        ang = NORM_ANGLE(fix16_to_int(pp->q16ang) + sop->clipbox_ang[i]);

        xs = pp->posx;
        ys = pp->posy;

        xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
        yvect = (sop->clipbox_vdist[i] * sintable[ang]);
        ret_start = clipmove_old(&xs, &ys, &z, &pp->cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);

        // save off the start position
        ox[i] = x[i] = xs;
        oy[i] = y[i] = ys;

        // move the box
        ret[i] = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);

        // save the dist moved
        dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
        //dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);

        if (ret[i])
        {
            //DSPRINTF(ds,"i %d, ret %d, dist %d",i, ret[i], dist);
            //printf("%s\n",ds);
            MONO_PRINT(ds);
        }

        if (dist < min_dist)
        {
            min_dist = dist;
            min_ndx = i;
        }
    }

    // put posx and y off from offset
    pp->posx -= ox[min_ndx] - x[min_ndx];
    pp->posy -= oy[min_ndx] - y[min_ndx];

    return ret[min_ndx];
}
#endif

#if 0
int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
    int i;
    int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
    SPRITEp sp = pp->sop->sp_child;
    USERp u = User[sp - sprite];
    SECTOR_OBJECTp sop = pp->sop;
    short ang;
    short min_ndx;
    int min_dist = 999999;
    int dist;

    int ret_start;
    int ret[MAX_CLIPBOX];
    int x[MAX_CLIPBOX],y[MAX_CLIPBOX];

    int xvect,yvect;
    int xs,ys;

    for (i = 0; i < sop->clipbox_num; i++)
    {
        // move the box to position instead of using offset- this prevents small rounding errors
        // allowing you to move through wall
        ang = NORM_ANGLE(fix16_to_int(pp->q16ang) + sop->clipbox_ang[i]);

        xs = pp->posx;
        ys = pp->posy;

        xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
        yvect = (sop->clipbox_vdist[i] * sintable[ang]);
        ret_start = clipmove_old(&xs, &ys, &z, &pp->cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);

        if (ret_start)
        {
            // hit something moving into position
            min_dist = 0;
            min_ndx = i;
            // ox is where it should be
            ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
            oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);

            x[i] = xs;
            y[i] = ys;

            dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
            //ox[i] = x[i] = oy[i] = y[i] = 0;
        }
        else
        {
            // save off the start position
            ox[i] = x[i] = xs;
            oy[i] = y[i] = ys;

            // move the box
            ret[i] = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);

            // save the dist moved
            dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
            //dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);

            if (ret[i])
            {
                //DSPRINTF(ds,"i %d, ret %d, dist %d",i, ret[i], dist);
                MONO_PRINT(ds);
            }

            if (dist < min_dist)
            {
                min_dist = dist;
                min_ndx = i;
            }
        }
    }

    // put posx and y off from offset
    pp->posx -= ox[min_ndx] - x[min_ndx];
    pp->posy -= oy[min_ndx] - y[min_ndx];

    return ret[min_ndx];
}
#endif

int MultiClipMove(PLAYERp pp, int z, int floor_dist)
{
    int i;
    int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
    SECTOR_OBJECTp sop = pp->sop;
    short ang;
    short min_ndx = 0;
    int min_dist = 999999;
    int dist;

    int ret_start;
    int ret;
    int min_ret=0;
    int x[MAX_CLIPBOX],y[MAX_CLIPBOX];

    int xvect,yvect;
    int xs,ys;

    for (i = 0; i < sop->clipbox_num; i++)
    {
        // move the box to position instead of using offset- this prevents small rounding errors
        // allowing you to move through wall
        ang = NORM_ANGLE(fix16_to_int(pp->q16ang) + sop->clipbox_ang[i]);

        xs = pp->posx;
        ys = pp->posy;

        xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
        yvect = (sop->clipbox_vdist[i] * sintable[ang]);
        clipmoveboxtracenum = 1;
        ret_start = clipmove_old(&xs, &ys, &z, &pp->cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
        clipmoveboxtracenum = 3;

        if (ret_start)
        {
            // hit something moving into start position
            min_dist = 0;
            min_ndx = i;
            // ox is where it should be
            ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
            oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);

            // xs is where it hit
            x[i] = xs;
            y[i] = ys;

            // see the dist moved
            dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));

            // save it off
            if (dist < min_dist)
            {
                min_dist = dist;
                min_ndx = i;
                min_ret = ret_start;
            }
        }
        else
        {
            // save off the start position
            ox[i] = x[i] = xs;
            oy[i] = y[i] = ys;

            // move the box
            ret = clipmove_old(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);

            // save the dist moved
            dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));

            if (ret)
            {
            }

            if (dist < min_dist)
            {
                min_dist = dist;
                min_ndx = i;
                min_ret = ret;
            }
        }
    }

    // put posx and y off from offset
    pp->posx += x[min_ndx] - ox[min_ndx];
    pp->posy += y[min_ndx] - oy[min_ndx];

    return min_ret;
}

short MultiClipTurn(PLAYERp pp, short new_ang, int z, int floor_dist)
{
    int i;
    SECTOR_OBJECTp sop = pp->sop;
    int ret;
    int x,y;
    short ang;
    int xvect, yvect;
    short cursectnum = pp->cursectnum;

    for (i = 0; i < sop->clipbox_num; i++)
    {
        ang = NORM_ANGLE(new_ang + sop->clipbox_ang[i]);

        x = pp->posx;
        y = pp->posy;

        xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
        yvect = (sop->clipbox_vdist[i] * sintable[ang]);

        // move the box
        ret = clipmove_old(&x, &y, &z, &cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);

        ASSERT(cursectnum >= 0);

        if (ret)
        {
            // attempt to move a bit when turning against a wall
            //ang = NORM_ANGLE(ang + 1024);
            //pp->xvect += 20 * sintable[NORM_ANGLE(ang + 512)];
            //pp->yvect += 20 * sintable[ang];
            return FALSE;
        }
    }

    return TRUE;
}

int testquadinsect(int *point_num, vec2_t const * q, short sectnum)
{
    int i,next_i;

    *point_num = -1;

    for (i=0; i < 4; i++)
    {
        if (!inside(q[i].x, q[i].y, sectnum))
        {
            ////DSPRINTF(ds,"inside %ld failed",i);
            //MONO_PRINT(ds);

            *point_num = i;

            return FALSE;
        }
    }

    for (i=0; i<4; i++)
    {
        next_i = MOD4(i+1);
        if (!cansee(q[i].x, q[i].y,0x3fffffff, sectnum,
                    q[next_i].x, q[next_i].y,0x3fffffff, sectnum))
        {
            DSPRINTF(ds,"cansee %ld failed, x1 %d, y1 %d, x2 %d, y2 %d, sectnum %d",i, q[i].x, q[i].y, q[next_i].x, q[next_i].y, sectnum);
            MONO_PRINT(ds);

            return FALSE;
        }
    }

    return TRUE;
}

//Ken gives the tank clippin' a try...
int RectClipMove(PLAYERp pp, int *qx, int *qy)
{
    int i;
    vec2_t xy[4];
    int point_num;

    for (i = 0; i < 4; i++)
    {
        xy[i].x = qx[i] + (pp->xvect>>14);
        xy[i].y = qy[i] + (pp->yvect>>14);
    }

    //Given the 4 points: x[4], y[4]
    if (testquadinsect(&point_num, xy, pp->cursectnum))
    {
        pp->posx += (pp->xvect>>14);
        pp->posy += (pp->yvect>>14);
        return TRUE;
    }

    if (point_num < 0)
        return FALSE;

    if ((point_num == 0) || (point_num == 3))   //Left side bad - strafe right
    {
        for (i = 0; i < 4; i++)
        {
            xy[i].x = qx[i] - (pp->yvect>>15);
            xy[i].y = qy[i] + (pp->xvect>>15);
        }
        if (testquadinsect(&point_num, xy, pp->cursectnum))
        {
            pp->posx -= (pp->yvect>>15);
            pp->posy += (pp->xvect>>15);
        }

        return FALSE;
    }

    if ((point_num == 1) || (point_num == 2))   //Right side bad - strafe left
    {
        for (i = 0; i < 4; i++)
        {
            xy[i].x = qx[i] + (pp->yvect>>15);
            xy[i].y = qy[i] - (pp->xvect>>15);
        }
        if (testquadinsect(&point_num, xy, pp->cursectnum))
        {
            pp->posx += (pp->yvect>>15);
            pp->posy -= (pp->xvect>>15);
        }

        return FALSE;
    }

    return FALSE;
}

int testpointinquad(int x, int y, int *qx, int *qy)
{
    int i, cnt, x1, y1, x2, y2;

    cnt = 0;
    for (i=0; i<4; i++)
    {
        y1 = qy[i]-y;
        y2 = qy[(i+1)&3]-y;
        if ((y1^y2) >= 0) continue;

        x1 = qx[i]-x;
        x2 = qx[(i+1)&3]-x;
        if ((x1^x2) >= 0)
            cnt ^= x1;
        else
            cnt ^= (x1*y2-x2*y1)^y2;
    }
    return cnt>>31;
}

short RectClipTurn(PLAYERp pp, short new_ang, int *qx, int *qy, int *ox, int *oy)
{
    int i;
    vec2_t xy[4];
    SECTOR_OBJECTp sop = pp->sop;
    short rot_ang;
    int point_num;

    rot_ang = NORM_ANGLE(new_ang + sop->spin_ang - sop->ang_orig);
    for (i = 0; i < 4; i++)
    {
        vec2_t const p = { ox[i], oy[i] };
        rotatepoint(pp->pos.xy, p, rot_ang, &xy[i]);
        // cannot use sop->xmid and ymid because the SO is off the map at this point
        //rotatepoint(sop->mid.pos2, p, rot_ang, &xy[i]);
    }

    //Given the 4 points: x[4], y[4]
    if (testquadinsect(&point_num, xy, pp->cursectnum))
    {
        // move to new pos
        for (i = 0; i < 4; i++)
        {
            qx[i] = xy[i].x;
            qy[i] = xy[i].y;
        }
        return TRUE;
    }

    if (point_num < 0)
        return FALSE;

    return FALSE;
}


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 RECT_CLIP 1

int MultiClipMove(PLAYERp pp, int z, int floor_dist);
short MultiClipTurn(PLAYERp pp, short new_ang, int z, int floor_dist);
int testquadinsect(int *point_num, vec2_t const * q, short sectnum);
int RectClipMove(PLAYERp pp, int *qx, int *qy);
int testpointinquad(int x, int y, int *qx, int *qy);
//short RectClipTurn(PLAYERp pp, short new_ang, int z, int floor_dist, int *qx, int *qy);
short RectClipTurn(PLAYERp pp, short new_ang, int *qx, int *qy, int *ox, int *oy);


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 "mytypes.h"
#include "keys.h"
#include "names2.h"
//#include "panel.h"
#include "game.h"

// macros this function needs
//#define MK_FP(seg,ofs)       ((void _seg *)(seg)+(void near *)(ofs))
//#define PokeByte(a,b,c)      (*((char far *)MK_FP((a),(b)))=(char)(c))

//#if DEBUG
void
PokeStringMono(uint8_t /*Attr*/, uint8_t* String)
{
    fprintf(stderr,"MONO: %s\n",String);
#if 0
    // Scrolls the monochrome display up one line, then prints the
    // string with the desired attribute on the bottom line.

    // EXAMPLE: PokeStringMono(MDA_NORMAL, "Hello, world.");

    uint8_t* Src, Dest;
    int32_t* s,d;
    static char MonoBuf[4000];

#define BASE (MonoBuf)
#define LINE_SIZE 160
#define LINE_OFFSET(num) ((80*2)*(num))

    // First scroll the screen up one line.
    // copy lines 1-24 up to 0
    s = (int32_t*)(BASE + LINE_SIZE);
    d = (int32_t*)BASE;
    memmove(d,s,LINE_OFFSET(24));

    // clear bottom line
    Dest = BASE + LINE_OFFSET(24);
    //memset(Dest,0,LINE_SIZE);
    memset(Dest,'.',LINE_SIZE);

    // Now print the string on the bottom line.
    Src = String;
    Dest = BASE + LINE_OFFSET(24);

    while (*Src)
    {
        *Dest++ = *Src++;
        *Dest++ = Attr;
    }

    memcpy((char *)0xB0000, MonoBuf, sizeof(MonoBuf));
#endif
}
//#endif