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

// MENUS.H
// Contains type definitions for all pop up menus

#ifndef MENUS_PUBLIC_
#define MENUS_PUBLIC_

#define MENU_SHADE_DEFAULT 0
#define MENU_SHADE_INACTIVE 20

typedef enum
{
    ct_mainmenu, ct_savemenu, ct_loadmenu, ct_soundmenu, ct_optionmenu, ct_quickloadmenu,
    ct_quitmenu, ct_ordermenu, ct_episodemenu, ct_max
} CTLType;

extern SWBOOL UsingMenus;
extern int SENSITIVITY;
extern CTLType ControlPanelType;
extern int16_t MenuTextShade;
extern int16_t MenuTextPalette;

// Prototypes
//void MNU_DoMenu( CTLType type );
void MNU_InitMenus(void);
//void (*CustomRefresh)(void);
//void MNU_Refresh( void );
void MNU_DrawMenu(void);    // This is used in drawscreen to refresh menus in
// multiplay situations.
void MNU_CheckForMenus(void);
void MNU_CheckForMenusAnyKey(void);
void MNU_MeasureString(const char *string, short *w, short *h);
void MNU_DrawString(short x, short y, const char *string, short shade, short pal);
void MNU_MeasureSmallString(const char *string,short *w,short *h);
void MNU_DrawSmallString(short x,short y,const char *string,short shade,short pal);
void MNU_MeasureStringLarge(const char *string, short *w, short *h);
void MNU_DrawStringLarge(short x, short y, const char *string);

// Functions from my other engine
//void Get_Palette (unsigned char *pal);
//void Set_Palette(unsigned char *buff);
//void Fade_Timer(int clicks);
void FadeIn(unsigned char targetcolor, unsigned int clicks);
void FadeOut(unsigned char targetcolor, unsigned int clicks);
void ResetPalette(PLAYERp pp);

void ExitMenus(void);
void ResetMenuInput(void);

extern SWBOOL BorderAdjust;
extern SWBOOL MultiPlayQuitFlag;

// Make memcpy an intrinsic function for an easy frame rate boost
//#pragma intrinsic( memcpy );

// L O C A L   V A R I A B L E S ////////////////////////////////////////////////////////////////

// Default menu pic brightness
#define m_defshade      2

#define FLASHTIME       60      // One second per icon flash

// Defines for permanentwritesprite clipping box
#define M_CX1   0
#define M_CY1   0
#define M_CX2   319
#define M_CY2   199

#define MZ              65536

#define asc_Esc         27
#define asc_Enter       13
#define asc_Space       32

#define pic_none 0
#define pic_radiobuttn1 2816
#define pic_radiobuttn2 2817
#define pic_newgame 2819
#define pic_load 2820
#define pic_save 2821
#define pic_options 2822
#define pic_orderinfo 2823
#define pic_todemo 2824
#define pic_togame 2825
#define pic_quit 2826
#define pic_newgametitl 2827
#define pic_training 2828
#define pic_easy 2829
#define pic_normal 2830
#define pic_hard 2831
#define pic_impossible 2832
#define pic_optionstitl 2833
#define pic_endgame 2834
#define pic_detail 2835
#define pic_high 2836
#define pic_low 2837
#define pic_mousesense 2838
#define pic_soundvol 2839
#define pic_toggles 2845
#define pic_togglestitl 2844
#define pic_mousenable 2840
#define pic_joyenable 2841
#define pic_bobbing 2842
#define pic_slidelend 2846
#define pic_slidebar 2847
#define pic_sliderend 2848
#define pic_sliderknob 2849
#define pic_shuriken1 2850
#define pic_yinyang 2870
#define pic_soundtitl 2870
#define pic_sndfxvol 2871
#define pic_musicvol 2872
#define pic_episode1 2873
#define pic_episode2 2874
#define pic_episode3 2875
#define pic_modem 2876
#define pic_scrsize 2877
#define pic_loadsavecursor 2918
#define pic_loadgame 2915
#define pic_savegame 2916
#define pic_loading 2917
#define pic_loadsavescreen 2919
#define pic_loadsavescreenbak 2922
#define pic_savedescr 2924
#define pic_shadow_warrior 2366

// This is the current values set with all slider bar functions
#define SENSE_DEFAULT   10  // Default mouse sensitivity ** should be 5!!!
#define FXVOL_DEFAULT   8   // Default sound fx volume
#define MUSIC_DEFAULT   8   // Default music volume
#define SCRSIZE_DEFAULT 9   // Default screen size, max is 10
#define BRIGHTNESS_DEFAULT 0 // Default is no gamma-correction
#define BORDERTILE_DEFAULT 0 // Default is no gamma-correction
#define GAMETYPE_DEFAULT 0  // Regular DeathMatch
#define NETLEVEL_DEFAULT 0  // Default is level 1 (0)
#define MONSTERS_DEFAULT 0  // No Monsters
#define KILLLIMIT_DEFAULT 0 // No kill limit
#define TIMELIMIT_DEFAULT 0 // None
#define PLAYERCOLOR_DEFAULT 0

typedef enum
{
    sldr_none,
    sldr_mouse, sldr_sndfxvolume, sldr_musicvolume, sldr_scrsize, sldr_brightness,
    sldr_bordertile, sldr_gametype, sldr_netlevel, sldr_monsters, sldr_killlimit,
    sldr_timelimit, sldr_playercolor, sldr_videores, sldr_videobpp,
    sldr_fov,
    sldr_mousescalex, sldr_mousescaley,
    sldr_joyaxisscale, sldr_joyaxisanalog, sldr_joyaxisdead, sldr_joyaxissatur,
    sldr_max
} SLDRType;

#define MAX_SLDR_WIDTH  16  // maximum size of slider before x is compressed

#define SLDR_MOUSESENSEMAX              20
#define SLDR_SNDFXVOLMAX                16
#define SLDR_MUSICVOLMAX                16
#define SLDR_SCRSIZEMAX                 14
#define SLDR_BRIGHTNESSMAX              8
#define SLDR_BORDERTILEMAX              (SW_SHAREWARE ? 21 : 38) // counted from border.c
#define SLDR_GAMETYPEMAX                3

#define SLDR_NETLEVELMAX_REG             28
#define SLDR_NETLEVELMAX_SW              4
#define SLDR_NETLEVELMAX                (SW_SHAREWARE ? SLDR_NETLEVELMAX_SW : SLDR_NETLEVELMAX_REG)

#define SLDR_MONSTERSMAX                5   // Skill Levels
#define SLDR_KILLLIMITMAX               11  // Increments of 10 up to 100, 1 is no limit
#define SLDR_TIMELIMITMAX               9
#define SLDR_PLAYERCOLORMAX             8   // Up to 8 players different colors

#define MOUSE_SENS_MAX_VALUE (1<<16)
#define MUSIC_VOL_MAX_VALUE 255
#define FX_VOL_MAX_VALUE 255

// These are all the toggle button settings
typedef enum
{
    btn_none, btn_auto_run, btn_crosshair, btn_auto_aim,
    btn_mouse_aim, btn_messages, btn_mouse_invert, btn_bobbing, btn_shadows,
    btn_sound, btn_music, btn_talking, btn_ambience, btn_flipstereo,
    btn_res0, btn_res1, btn_res2, btn_res3, btn_res4, btn_res5, btn_res6,
    btn_markers, btn_teamplay, btn_friendlyfire,btn_parental,btn_nuke,
    btn_voxels, btn_stats, btn_playcd,
    btn_videofs,
    btn_darts,
    btn_autoswitch,
    btn_interpolate_so,
    btn_max
} BTNType;

enum
{
    mf_normal = BIT(0),
    mf_pushed = BIT(1),
    mf_selected = BIT(2),
    mf_disabled = BIT(3),
    mf_separated = BIT(4)
};
typedef int MenuFlags;

#define MenuSelectFlags (mf_pushed | mf_selected | mf_disabled)
#define MenuDrawFlags (ROTATE_SPRITE_SCREEN_CLIP)

typedef enum
{
    mt_none,
    mt_inert, mt_slider, mt_button, mt_option, mt_layer
} MenuTag;

typedef enum
{
    uc_setup, uc_draw, uc_touchup, uc_hit
} UserCall;

struct MenuGroup;

typedef struct MENU_ITEM
{
    MenuTag type;                       // What kind of item is this on the
    // menu?
    MenuFlags flags;                    // Menu item flags
    SLDRType slider;                    // Slider type, if any
    BTNType button;                     // Button state, if any
    unsigned char hotkey;               // First letter of item
    const char *text;                   // Text appearing in item, if any.
    MenuGroup *child;                        // Should be menugroup, used to spawn
    // sub-groups from items.
    int x, y;                          // x,y position on screen.
    short pic;                        // Startpic to use
    char shade;                         // Shade of pic
    int tics;                          // Ticcount for item
    SWBOOL(*custom)(void);               // Work function on item select

    SWBOOL (*preprocess)(struct MENU_ITEM *);
    SWBOOL (*postprocess)(struct MENU_ITEM *); // Can do things on items select
} MenuItem, *MenuItem_p;

typedef struct MenuGroup
{
    int x, y;                          // Menu x,y position on screen.
    const char *text;
    MenuItem_p items;                   // Array of menu items for this menu.
    short titlepic;                   // Used to draw title on menu with.
    short cursorpic;                  // Pic used for menu cursor, 1st in
    // anim sequence if animated.
    char shade;                         // Title pic shade

    SWBOOL(*draw_custom)(UserCall, MenuItem *);       // Custom routine
    SWBOOL(*move_custom)(UserCall, MenuItem *);       // Custom routine

    short cursor;                       // This is the current menu item the
    // cursor is resting on.
} MenuGroup, *MenuGroup_p;

// Custom Routine Prototypes ////////////////////////////////////////////////////////////////////

SWBOOL MNU_QuitCustom(UserCall call, MenuItem *item);
SWBOOL MNU_QuickLoadCustom(UserCall call, MenuItem *item);
SWBOOL MNU_LoadSaveTouchupCustom(UserCall call, MenuItem *item);
SWBOOL MNU_DoParentalPassword(UserCall call, MenuItem *item);
SWBOOL MNU_OrderCustom(UserCall call, MenuItem *item);
SWBOOL MNU_DoEpisodeSelect(UserCall call, MenuItem *item);

SWBOOL MNU_MusicFxCheck(MenuItem_p item);
SWBOOL MNU_MusicCheck(MenuItem_p item);
SWBOOL MNU_FxCheck(MenuItem_p item);
SWBOOL MNU_MouseCheck(MenuItem_p item);
SWBOOL MNU_JoystickCheck(MenuItem_p item);
SWBOOL MNU_BorderCheck(MenuItem_p item);
SWBOOL MNU_ShareWareCheck(MenuItem_p item);
SWBOOL MNU_MenuLevelCheck(MenuItem_p item);
SWBOOL MNU_ShareWareMessage(MenuItem_p item);

// Custom MenuItem Routines /////////////////////////////////////////////////////////////////////

SWBOOL MNU_StartGame(void);
SWBOOL MNU_StartNetGame(void);
SWBOOL MNU_EpisodeCustom(void);
SWBOOL MNU_GetDescripCustom(void);
SWBOOL MNU_LoadGameCustom(void);
SWBOOL MNU_SaveGameCustom(void);
SWBOOL MNU_GetLoadCustom(void);
SWBOOL MNU_GetSaveCustom(void);
SWBOOL MNU_ParentalCustom(void);
SWBOOL MNU_KeySetupCustom(UserCall call, MenuItem *item);
SWBOOL MNU_LoadModernDefaults(void);
SWBOOL MNU_LoadClassicDefaults(void);

// Menu Definitions /////////////////////////////////////////////////////////////////////////////

#define DefInert(key,text)          mt_inert,mf_normal,sldr_none,btn_none,key,text,NULL
#define DefSlider(slider,key,text)  mt_slider,mf_normal,slider,btn_none,key,text,NULL
#define DefOption(key,text)         mt_option,mf_normal,sldr_none,btn_none,key,text,NULL
#define DefButton(button,key,text)  mt_button,mf_normal,sldr_none,button,key,text,NULL
#define DefLayer(key,text,child)    mt_layer,mf_normal,sldr_none,btn_none,key,text,child

#define DefDisabled(key,text,child)    mt_layer,mf_disabled,sldr_none,btn_none,key,text,child
#define DefNone mt_none,(MenuFlags)0,(SLDRType)0,(BTNType)0,0,NULL,NULL,0,0,0,0,0,NULL,NULL,NULL

#define OPT_XS 30
#define OPT_YS 30
#define OPT_XSIDE (OPT_XS + 120)
#define OPT_YINC 10
#define OPT_LINE(line) (OPT_YS + (OPT_YINC * (line)))

typedef struct
{
    int x,y;
} VMODE;

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

#include "compat.h"
#include "cache1d.h"

typedef BFILE* MFILE_WRITE;
typedef int32_t MFILE_READ;
#define MREAD(ptr, size, num,handle) kdfread((ptr),(size),(num),(handle))
#define MWRITE(ptr, size, num,handle) dfwrite((ptr),(size),(num),(handle))
#define MOPEN_WRITE(name) Bfopen(name,"wb")
#define MOPEN_READ(name) kopen4load(name,0)
#define MCLOSE_WRITE(handle) Bfclose(handle)
#define MCLOSE_READ(handle) kclose(handle)
#define MOPEN_WRITE_ERR 0
#define MOPEN_READ_ERR -1


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 "tags.h"
#include "ai.h"
#include "quake.h"
#include "fx_man.h"
#include "actor.h"
#include "sector.h"
#include "sprite.h"

ANIMATOR NullToiletGirl;

ATTRIBUTE ToiletGirlAttrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    3,                               // MaxWeapons;
    {
        0, 0, DIGI_TOILETGIRLSCREAM,
        DIGI_TOILETGIRLPAIN, DIGI_TOILETGIRLSCREAM, 0,0,0,0,0
    }
};

//////////////////////
//
// TOILETGIRL STAND
//
//////////////////////
#define TOILETGIRL_RATE 60
ANIMATOR NullToiletGirl,DoToiletGirl;

STATE s_ToiletGirlStand[2] =
{
    {TOILETGIRL_R0 + 0, TOILETGIRL_RATE, DoToiletGirl, &s_ToiletGirlStand[1]},
    {TOILETGIRL_R0 + 1, TOILETGIRL_RATE, DoToiletGirl, &s_ToiletGirlStand[0]}
};

//////////////////////
//
// TOILETGIRL PAIN
//
//////////////////////

#define TOILETGIRL_PAIN_RATE 32
#define TOILETGIRL_PAIN_R0 TOILETGIRL_R0
ANIMATOR ToiletGirlPain;

STATE s_ToiletGirlPain[2] =
{
    {TOILETGIRL_PAIN_R0 + 0, TOILETGIRL_PAIN_RATE, ToiletGirlPain, &s_ToiletGirlPain[1]},
    {TOILETGIRL_PAIN_R0 + 0, 0|SF_QUICK_CALL, InitActorDecide, &s_ToiletGirlPain[0]}
};

//////////////////////
//
// TOILETGIRL UZI
//
//////////////////////

#define TOILETGIRL_UZI_RATE 8
#define TOILETGIRL_FIRE_R0 TOILETGIRL_R0 + 2
ANIMATOR InitEnemyUzi,ToiletGirlUzi;

STATE s_ToiletGirlUzi[16] =
{
    {TOILETGIRL_FIRE_R0 + 0, TOILETGIRL_UZI_RATE, ToiletGirlUzi, &s_ToiletGirlUzi[1]},
    {TOILETGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_ToiletGirlUzi[2]},
    {TOILETGIRL_FIRE_R0 + 1, TOILETGIRL_UZI_RATE, ToiletGirlUzi, &s_ToiletGirlUzi[3]},
    {TOILETGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_ToiletGirlUzi[4]},
    {TOILETGIRL_FIRE_R0 + 0, TOILETGIRL_UZI_RATE, ToiletGirlUzi, &s_ToiletGirlUzi[5]},
    {TOILETGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_ToiletGirlUzi[6]},
    {TOILETGIRL_FIRE_R0 + 1, TOILETGIRL_UZI_RATE, ToiletGirlUzi, &s_ToiletGirlUzi[7]},
    {TOILETGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_ToiletGirlUzi[8]},
    {TOILETGIRL_FIRE_R0 + 0, TOILETGIRL_UZI_RATE, ToiletGirlUzi, &s_ToiletGirlUzi[9]},
    {TOILETGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_ToiletGirlUzi[10]},
    {TOILETGIRL_FIRE_R0 + 1, TOILETGIRL_UZI_RATE, ToiletGirlUzi, &s_ToiletGirlUzi[11]},
    {TOILETGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_ToiletGirlUzi[12]},
    {TOILETGIRL_FIRE_R0 + 0, TOILETGIRL_UZI_RATE, ToiletGirlUzi, &s_ToiletGirlUzi[13]},
    {TOILETGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_ToiletGirlUzi[14]},
    {TOILETGIRL_FIRE_R0 + 1, TOILETGIRL_UZI_RATE, ToiletGirlUzi, &s_ToiletGirlUzi[15]},
    {TOILETGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_ToiletGirlUzi[0]},
};

int
SetupToiletGirl(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,TOILETGIRL_R0,s_ToiletGirlStand);
        u->Health = 60;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_ToiletGirlStand);
    u->Attrib = &ToiletGirlAttrib;
    u->StateEnd = s_ToiletGirlStand;
    u->Rot = 0;
    u->RotNum = 0;

    sp->xrepeat = 38;
    sp->yrepeat = 32;
    sp->xvel = sp->yvel = sp->zvel = 0;
    sp->lotag = TOILETGIRL_R0;
    u->FlagOwner = 0;
    u->ID = TOILETGIRL_R0;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);

    return 0;
}

int DoToiletGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,SPRITEp_MID(u->tgt_sp),u->tgt_sp->sectnum);

    if (u->FlagOwner != 1)
    {
        if (RANDOM_RANGE(1000) > 980)
        {
            static int handle;
            short choose_snd;

            choose_snd = RANDOM_P2(1024<<4)>>4;

            if (!FX_SoundValidAndActive(handle))
            {
                if (choose_snd > 750)
                    handle = PlaySound(DIGI_TOILETGIRLFART1,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else if (choose_snd > 350)
                    handle = PlaySound(DIGI_TOILETGIRLFART2,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else
                    handle = PlaySound(DIGI_TOILETGIRLFART3,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            }
        }
    }
    else if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
    {
        static int madhandle;

        if (!FX_SoundValidAndActive(madhandle))
        {
            if (RANDOM_RANGE(1000<<8)>>8 > 500)
                madhandle = PlaySound(DIGI_ANIMEMAD1,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else
                madhandle = PlaySound(DIGI_ANIMEMAD2,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }
        ChangeState(SpriteNum,s_ToiletGirlUzi);
        u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(3<<8)>>8);
        u->FlagOwner = 0;
    }

    //(*u->ActorActionFunc) (SpriteNum);

    // stay on floor unless doing certain things
    if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING | SPR_CLIMBING))
    {
        KeepActorOnFloor(SpriteNum);
    }

    // take damage from environment
    DoActorSectorDamage(SpriteNum);
    sp->xvel = sp->yvel = sp->zvel = 0;

    return 0;
}

int NullToiletGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,u->tgt_sp->z,u->tgt_sp->sectnum);

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if (u->FlagOwner != 1)
    {
    }
    else if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
    {
        static int madhandle;

        if (!FX_SoundValidAndActive(madhandle))
        {
            if (RANDOM_RANGE(1000<<8)>>8 > 500)
                madhandle = PlaySound(DIGI_ANIMEMAD1,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else
                madhandle = PlaySound(DIGI_ANIMEMAD2,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }
        ChangeState(SpriteNum,s_ToiletGirlUzi);
        u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(3<<8)>>8);
        u->FlagOwner = 0;
    }

    return 0;
}

int ToiletGirlUzi(short SpriteNum)
{
    USERp u = User[SpriteNum];

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
    {
        u->WaitTics = RANDOM_RANGE(240)+120;
        ChangeState(SpriteNum,s_ToiletGirlStand);
        u->FlagOwner = 0;
    }

    return 0;
}

int ToiletGirlPain(short SpriteNum)
{
    USERp u = User[SpriteNum];

    NullToiletGirl(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
        ChangeState(SpriteNum,s_ToiletGirlStand);

    return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////

ANIMATOR NullWashGirl;

ATTRIBUTE WashGirlAttrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    3,                               // MaxWeapons;
    {
        0, 0, DIGI_TOILETGIRLSCREAM,
        DIGI_TOILETGIRLPAIN, DIGI_TOILETGIRLSCREAM, 0,0,0,0,0
    }
};

//////////////////////
//
// WASHGIRL STAND
//
//////////////////////
#define WASHGIRL_RATE 60
ANIMATOR NullWashGirl,DoWashGirl;

STATE s_WashGirlStand[2] =
{
    {WASHGIRL_R0 + 0, WASHGIRL_RATE, DoWashGirl, &s_WashGirlStand[1]},
    {WASHGIRL_R0 + 1, WASHGIRL_RATE, DoWashGirl, &s_WashGirlStand[0]}
};

#define WASHGIRL_RATE2 20
STATE s_WashGirlStandScrub[2] =
{
    {WASHGIRL_R0 + 0, WASHGIRL_RATE2, DoWashGirl, &s_WashGirlStandScrub[1]},
    {WASHGIRL_R0 + 1, WASHGIRL_RATE2, DoWashGirl, &s_WashGirlStandScrub[0]}
};

//////////////////////
//
// WASHGIRL PAIN
//
//////////////////////

#define WASHGIRL_PAIN_RATE 30
#define WASHGIRL_PAIN_R0 WASHGIRL_R0
ANIMATOR WashGirlPain;

STATE s_WashGirlPain[2] =
{
    {WASHGIRL_PAIN_R0 + 0, WASHGIRL_PAIN_RATE, WashGirlPain, &s_WashGirlPain[1]},
    {WASHGIRL_PAIN_R0 + 0, 0|SF_QUICK_CALL, InitActorDecide, &s_WashGirlPain[0]}
};

//////////////////////
//
// WASHGIRL UZI
//
//////////////////////

#define WASHGIRL_UZI_RATE 8
#define WASHGIRL_FIRE_R0 WASHGIRL_R0 + 2
ANIMATOR InitEnemyUzi,WashGirlUzi;

STATE s_WashGirlUzi[16] =
{
    {WASHGIRL_FIRE_R0 + 0, WASHGIRL_UZI_RATE, WashGirlUzi, &s_WashGirlUzi[1]},
    {WASHGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_WashGirlUzi[2]},
    {WASHGIRL_FIRE_R0 + 1, WASHGIRL_UZI_RATE, WashGirlUzi, &s_WashGirlUzi[3]},
    {WASHGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_WashGirlUzi[4]},
    {WASHGIRL_FIRE_R0 + 0, WASHGIRL_UZI_RATE, WashGirlUzi, &s_WashGirlUzi[5]},
    {WASHGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_WashGirlUzi[6]},
    {WASHGIRL_FIRE_R0 + 1, WASHGIRL_UZI_RATE, WashGirlUzi, &s_WashGirlUzi[7]},
    {WASHGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_WashGirlUzi[8]},
    {WASHGIRL_FIRE_R0 + 0, WASHGIRL_UZI_RATE, WashGirlUzi, &s_WashGirlUzi[9]},
    {WASHGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_WashGirlUzi[10]},
    {WASHGIRL_FIRE_R0 + 1, WASHGIRL_UZI_RATE, WashGirlUzi, &s_WashGirlUzi[11]},
    {WASHGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_WashGirlUzi[12]},
    {WASHGIRL_FIRE_R0 + 0, WASHGIRL_UZI_RATE, WashGirlUzi, &s_WashGirlUzi[13]},
    {WASHGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_WashGirlUzi[14]},
    {WASHGIRL_FIRE_R0 + 1, WASHGIRL_UZI_RATE, WashGirlUzi, &s_WashGirlUzi[15]},
    {WASHGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_WashGirlUzi[0]},
};

int
SetupWashGirl(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,WASHGIRL_R0,s_WashGirlStand);
        u->Health = 60;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_WashGirlStand);
    u->Attrib = &WashGirlAttrib;
    u->StateEnd = s_WashGirlStand;
    u->Rot = 0;
    u->RotNum = 0;

    sp->xrepeat = 28;
    sp->yrepeat = 24;
    sp->xvel = sp->yvel = sp->zvel = 0;
    sp->lotag = WASHGIRL_R0;
    u->FlagOwner = 0;
    u->ID = WASHGIRL_R0;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);

    return 0;
}

int DoWashGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,SPRITEp_MID(u->tgt_sp),u->tgt_sp->sectnum);

    if (RANDOM_RANGE(1000) > 980 && u->ShellNum <= 0)
    {
        static int handle;

        if (!FX_SoundValidAndActive(handle))
        {
            if (RANDOM_P2(1024<<4)>>4 > 500)
                handle = PlaySound(DIGI_ANIMESING1,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else
                handle = PlaySound(DIGI_ANIMESING2,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }

        ChangeState(SpriteNum,s_WashGirlStandScrub);
        u->ShellNum = RANDOM_RANGE(2*120)+240;
    }
    else
    {
        if (u->ShellNum > 0)
        {
            if ((u->ShellNum -= ACTORMOVETICS) < 0)
            {
                ChangeState(SpriteNum,s_WashGirlStand);
                u->ShellNum = 0;
            }
        }
    }

    if (u->FlagOwner != 1)
    {
    }
    else if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
    {
        static int madhandle;

        if (!FX_SoundValidAndActive(madhandle))
        {
            if (RANDOM_RANGE(1000<<8)>>8 > 500)
                madhandle = PlaySound(DIGI_ANIMEMAD1,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else
                madhandle = PlaySound(DIGI_ANIMEMAD2,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }
        ChangeState(SpriteNum,s_WashGirlUzi);
        u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(3<<8)>>8);
        u->FlagOwner = 0;
    }

    // stay on floor unless doing certain things
    if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING | SPR_CLIMBING))
    {
        KeepActorOnFloor(SpriteNum);
    }

    // take damage from environment
    DoActorSectorDamage(SpriteNum);
    sp->xvel = sp->yvel = sp->zvel = 0;

    return 0;
}

int NullWashGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,u->tgt_sp->z,u->tgt_sp->sectnum);

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if (u->FlagOwner != 1)
    {
    }
    else if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
    {
        static int madhandle;

        if (!FX_SoundValidAndActive(madhandle))
        {
            if (RANDOM_RANGE(1000<<8)>>8 > 500)
                madhandle = PlaySound(DIGI_ANIMEMAD1,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else
                madhandle = PlaySound(DIGI_ANIMEMAD2,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }
        ChangeState(SpriteNum,s_WashGirlUzi);
        u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(3<<8)>>8);
        u->FlagOwner = 0;
    }

    return 0;
}

int WashGirlUzi(short SpriteNum)
{
    USERp u = User[SpriteNum];

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
    {
        u->WaitTics = RANDOM_RANGE(240)+120;
        ChangeState(SpriteNum,s_WashGirlStand);
        u->FlagOwner = 0;
    }

    return 0;
}

int WashGirlPain(short SpriteNum)
{
    USERp u = User[SpriteNum];

    NullWashGirl(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
        ChangeState(SpriteNum,s_WashGirlStand);

    return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////

ATTRIBUTE TrashCanAttrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    0,                               // MaxWeapons;
    {0, 0, DIGI_TRASHLID, DIGI_TRASHLID, 0, 0,0,0,0,0}
};

//////////////////////
//
// TRASHCAN STAND
//
//////////////////////
#define TRASHCAN_RATE 120
#define TRASHCAN_R0 TRASHCAN
ANIMATOR NullTrashCan,DoTrashCan;

STATE s_TrashCanStand[1] =
{
    {TRASHCAN_R0 + 0, TRASHCAN_RATE, DoTrashCan, &s_TrashCanStand[0]}
};

//////////////////////
//
// TRASHCAN PAIN
//
//////////////////////

#define TRASHCAN_PAIN_RATE 8
#define TRASHCAN_PAIN_R0 TRASHCAN
ANIMATOR TrashCanPain, TrashCanStand;

STATE s_TrashCanPain[7] =
{
    {TRASHCAN_PAIN_R0 + 0, TRASHCAN_PAIN_RATE, TrashCanPain, &s_TrashCanPain[1]},
    {TRASHCAN_PAIN_R0 + 1, TRASHCAN_PAIN_RATE, TrashCanPain, &s_TrashCanPain[2]},
    {TRASHCAN_PAIN_R0 + 2, TRASHCAN_PAIN_RATE, TrashCanPain, &s_TrashCanPain[3]},
    {TRASHCAN_PAIN_R0 + 3, TRASHCAN_PAIN_RATE, TrashCanPain, &s_TrashCanPain[4]},
    {TRASHCAN_PAIN_R0 + 4, TRASHCAN_PAIN_RATE, TrashCanPain, &s_TrashCanPain[5]},
    {TRASHCAN_PAIN_R0 + 5, TRASHCAN_PAIN_RATE, TrashCanPain, &s_TrashCanPain[6]},
    {TRASHCAN_PAIN_R0 + 6, TRASHCAN_PAIN_RATE, TrashCanPain, &s_TrashCanPain[0]}
};

int
SetupTrashCan(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,TRASHCAN,s_TrashCanStand);
        u->Health = 60;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_TrashCanStand);
    u->Attrib = &TrashCanAttrib;
    u->StateEnd = s_TrashCanStand;
    u->Rot = 0;
    u->RotNum = 0;

    sp->xrepeat = 46;
    sp->yrepeat = 42;
    sp->xvel = sp->yvel = sp->zvel = 0;
    u->ID = TRASHCAN;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);
    RESET(sp->extra, SPRX_PLAYER_OR_ENEMY);

    return 0;
}

int DoTrashCan(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;

    //(*u->ActorActionFunc) (SpriteNum);

    // stay on floor unless doing certain things
    if (TEST(u->Flags,SPR_SLIDING))
        DoActorSlide(SpriteNum);

    if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING | SPR_CLIMBING))
    {
        KeepActorOnFloor(SpriteNum);
    }

    sp->xvel = sp->yvel = sp->zvel = 0;

    return 0;
}

int TrashCanPain(short SpriteNum)
{
    USERp u = User[SpriteNum];

    if (TEST(u->Flags,SPR_SLIDING))
        DoActorSlide(SpriteNum);

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
        ChangeState(SpriteNum,s_TrashCanStand);

    return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// PACHINKO WIN LIGHT
////////////////////////////////////////////////////////////////////
ATTRIBUTE PachinkoLightAttrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    0,                               // MaxWeapons;
    {0, 0, DIGI_TRASHLID, DIGI_TRASHLID, 0, 0,0,0,0,0}
};

#define PACHINKOLIGHT_RATE 120
#define PACHINKOLIGHT_R0 623

STATE s_PachinkoLightStand[] =
{
    {PACHINKOLIGHT_R0 + 0, PACHINKOLIGHT_RATE, NullAnimator, &s_PachinkoLightStand[0]}
};

ANIMATOR PachinkoLightOperate;
STATE s_PachinkoLightOperate[] =
{
    {PACHINKOLIGHT_R0 - 0, 12, PachinkoLightOperate, &s_PachinkoLightOperate[1]},
    {PACHINKOLIGHT_R0 - 1, 12, PachinkoLightOperate, &s_PachinkoLightOperate[2]},
    {PACHINKOLIGHT_R0 - 2, 12, PachinkoLightOperate, &s_PachinkoLightOperate[3]},
    {PACHINKOLIGHT_R0 - 3, 12, PachinkoLightOperate, &s_PachinkoLightOperate[4]},
    {PACHINKOLIGHT_R0 - 4, 12, PachinkoLightOperate, &s_PachinkoLightOperate[5]},
    {PACHINKOLIGHT_R0 - 5, 12, PachinkoLightOperate, &s_PachinkoLightOperate[0]},
};

int
SetupPachinkoLight(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,PACHINKOLIGHT_R0,s_PachinkoLightStand);
        u->Health = 1;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_PachinkoLightStand);
    u->Attrib = &PachinkoLightAttrib;
    u->StateEnd = s_PachinkoLightStand;
    u->Rot = 0;
    u->RotNum = 0;
    u->ID = PACHINKOLIGHT_R0;

    sp->xvel = sp->yvel = sp->zvel = 0;
    sp->lotag = TAG_PACHINKOLIGHT;
    sp->shade = -2;
    u->spal = sp->pal;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);
    RESET(sp->extra, SPRX_PLAYER_OR_ENEMY);

    return 0;
}

int PachinkoLightOperate(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u = User[SpriteNum];

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
    {
        sp->shade = -2;
        ChangeState(SpriteNum,s_PachinkoLightStand);
    }
    return 0;
}

////////////////////////////////////////////////////////////////////
// PACHINKO MACHINE #1
////////////////////////////////////////////////////////////////////

SWBOOL Pachinko_Win_Cheat = FALSE;

ATTRIBUTE Pachinko1Attrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    0,                               // MaxWeapons;
    {0, 0, DIGI_TRASHLID, DIGI_TRASHLID, 0, 0,0,0,0,0}
};

#define PACHINKO1_RATE 120
#define PACHINKO1_R0 PACHINKO1

STATE s_Pachinko1Stand[] =
{
    {PACHINKO1_R0 + 0, PACHINKO1_RATE, NullAnimator, &s_Pachinko1Stand[0]}
};

ANIMATOR Pachinko1Operate,PachinkoCheckWin;
STATE s_Pachinko1Operate[] =
{
    {PACHINKO1_R0 + 0, 12, Pachinko1Operate, &s_Pachinko1Operate[1]},
    {PACHINKO1_R0 + 1, 12, Pachinko1Operate, &s_Pachinko1Operate[2]},
    {PACHINKO1_R0 + 2, 12, Pachinko1Operate, &s_Pachinko1Operate[3]},
    {PACHINKO1_R0 + 3, 12, Pachinko1Operate, &s_Pachinko1Operate[4]},
    {PACHINKO1_R0 + 4, 12, Pachinko1Operate, &s_Pachinko1Operate[5]},
    {PACHINKO1_R0 + 5, 12, Pachinko1Operate, &s_Pachinko1Operate[6]},
    {PACHINKO1_R0 + 6, 12, Pachinko1Operate, &s_Pachinko1Operate[7]},
    {PACHINKO1_R0 + 7, 12, Pachinko1Operate, &s_Pachinko1Operate[8]},
    {PACHINKO1_R0 + 8, 12, Pachinko1Operate, &s_Pachinko1Operate[9]},
    {PACHINKO1_R0 + 9, 12, Pachinko1Operate, &s_Pachinko1Operate[10]},
    {PACHINKO1_R0 + 10, 12, Pachinko1Operate, &s_Pachinko1Operate[11]},
    {PACHINKO1_R0 + 11, 12, Pachinko1Operate, &s_Pachinko1Operate[12]},
    {PACHINKO1_R0 + 12, 12, Pachinko1Operate, &s_Pachinko1Operate[13]},
    {PACHINKO1_R0 + 13, 12, Pachinko1Operate, &s_Pachinko1Operate[14]},
    {PACHINKO1_R0 + 14, 12, Pachinko1Operate, &s_Pachinko1Operate[15]},
    {PACHINKO1_R0 + 15, 12, Pachinko1Operate, &s_Pachinko1Operate[16]},
    {PACHINKO1_R0 + 16, 12, Pachinko1Operate, &s_Pachinko1Operate[17]},
    {PACHINKO1_R0 + 17, 12, Pachinko1Operate, &s_Pachinko1Operate[18]},
    {PACHINKO1_R0 + 18, 12, Pachinko1Operate, &s_Pachinko1Operate[19]},
    {PACHINKO1_R0 + 19, 12, Pachinko1Operate, &s_Pachinko1Operate[20]},
    {PACHINKO1_R0 + 20, 12, Pachinko1Operate, &s_Pachinko1Operate[21]},
    {PACHINKO1_R0 + 21, 12, Pachinko1Operate, &s_Pachinko1Operate[22]},
    {PACHINKO1_R0 + 22, SF_QUICK_CALL, PachinkoCheckWin, &s_Pachinko1Stand[0]}
};

int
SetupPachinko1(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,PACHINKO1,s_Pachinko1Stand);
        u->Health = 1;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_Pachinko1Stand);
    u->Attrib = &Pachinko1Attrib;
    u->StateEnd = s_Pachinko1Stand;
    u->Rot = 0;
    u->RotNum = 0;
    u->ID = PACHINKO1;

    sp->yvel = sp->zvel = 0;
    sp->lotag = PACHINKO1;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);
    RESET(sp->extra, SPRX_PLAYER_OR_ENEMY);

    return 0;
}

int PachinkoCheckWin(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u = User[SpriteNum];

    u->WaitTics = 0;  // Can operate it again now

    //CON_ConMessage("bool1 = %d",TEST_BOOL1(sp));
    // You already won, no more from this machine!
    if (TEST_BOOL1(sp)) return 0;

    // Well? Did I win????!
    /*short rnd = */RANDOM_RANGE(1000);
    if (RANDOM_RANGE(1000) > 900 || Pachinko_Win_Cheat)
    {
        short i, nexti;
        SPRITEp tsp;
        USERp tu;

        // Do a possible combo switch
        if (ComboSwitchTest(TAG_COMBO_SWITCH_EVERYTHING, sp->hitag))
        {
            DoMatchEverything(Player+myconnectindex, sp->hitag, ON);
        }

        ActorCoughItem(SpriteNum); // I WON! I WON!
        PlaySound(DIGI_PALARM,&sp->x,&sp->y,&sp->z,v3df_none);

        // Can't win any more now!
        SET_BOOL1(sp);

        // Turn on the pachinko lights
        TRAVERSE_SPRITE_STAT(headspritestat[STAT_ENEMY], i, nexti)
        {
            tsp = &sprite[i];
            tu = User[i];

            if (tsp->lotag == TAG_PACHINKOLIGHT)
            {
                if (tsp->hitag == SP_TAG5(sp))
                {
                    tsp->shade = -90; // Full brightness
                    tu->WaitTics = SEC(3); // Flash
                    ChangeState(i,s_PachinkoLightOperate);
                }
            }
        }

    }

    //{
    //if(rnd > 950)
    //    PlayerSound(DIGI_SHISEISI,&pp->posx,&pp->posy,&pp->posz,v3df_follow|v3df_dontpan,pp);
    //else
    //if(rnd > 900)
    //    PlayerSound(DIGI_YOULOOKSTUPID,&pp->posx,&pp->posy,&pp->posz,v3df_follow|v3df_dontpan,pp);
    //else
    //if(rnd > 850)
    //    PlayerSound(DIGI_HURTBAD5,&pp->posx,&pp->posy,&pp->posz,v3df_follow|v3df_dontpan,pp);
    //}

    return 0;
}

int Pachinko1Operate(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    short rnd;

    rnd = RANDOM_RANGE(1000);
    if (rnd > 900)
    {
        rnd = RANDOM_RANGE(1000);  // TEMP SOUNDS: Need pachinko sounds!
        if (rnd > 700)
            PlaySound(DIGI_PROLL1,&sp->x,&sp->y,&sp->z,v3df_none);
        else if (rnd > 400)
            PlaySound(DIGI_PROLL2,&sp->x,&sp->y,&sp->z,v3df_none);
        else
            PlaySound(DIGI_PROLL3,&sp->x,&sp->y,&sp->z,v3df_none);
    }

    return 0;
}

////////////////////////////////////////////////////////////////////
// PACHINKO MACHINE #2
////////////////////////////////////////////////////////////////////

ATTRIBUTE Pachinko2Attrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    0,                               // MaxWeapons;
    {0, 0, DIGI_TRASHLID, DIGI_TRASHLID, 0, 0,0,0,0,0}
};

#define PACHINKO2_RATE 120
#define PACHINKO2_R0 PACHINKO2

STATE s_Pachinko2Stand[] =
{
    {PACHINKO2_R0 + 0, PACHINKO2_RATE, NullAnimator, &s_Pachinko2Stand[0]}
};

ANIMATOR Pachinko2Operate;
STATE s_Pachinko2Operate[] =
{
    {PACHINKO2_R0 + 0, 12, Pachinko1Operate, &s_Pachinko2Operate[1]},
    {PACHINKO2_R0 + 1, 12, Pachinko1Operate, &s_Pachinko2Operate[2]},
    {PACHINKO2_R0 + 2, 12, Pachinko1Operate, &s_Pachinko2Operate[3]},
    {PACHINKO2_R0 + 3, 12, Pachinko1Operate, &s_Pachinko2Operate[4]},
    {PACHINKO2_R0 + 4, 12, Pachinko1Operate, &s_Pachinko2Operate[5]},
    {PACHINKO2_R0 + 5, 12, Pachinko1Operate, &s_Pachinko2Operate[6]},
    {PACHINKO2_R0 + 6, 12, Pachinko1Operate, &s_Pachinko2Operate[7]},
    {PACHINKO2_R0 + 7, 12, Pachinko1Operate, &s_Pachinko2Operate[8]},
    {PACHINKO2_R0 + 8, 12, Pachinko1Operate, &s_Pachinko2Operate[9]},
    {PACHINKO2_R0 + 9, 12, Pachinko1Operate, &s_Pachinko2Operate[10]},
    {PACHINKO2_R0 + 10, 12, Pachinko1Operate, &s_Pachinko2Operate[11]},
    {PACHINKO2_R0 + 11, 12, Pachinko1Operate, &s_Pachinko2Operate[12]},
    {PACHINKO2_R0 + 12, 12, Pachinko1Operate, &s_Pachinko2Operate[13]},
    {PACHINKO2_R0 + 13, 12, Pachinko1Operate, &s_Pachinko2Operate[14]},
    {PACHINKO2_R0 + 14, 12, Pachinko1Operate, &s_Pachinko2Operate[15]},
    {PACHINKO2_R0 + 15, 12, Pachinko1Operate, &s_Pachinko2Operate[16]},
    {PACHINKO2_R0 + 16, 12, Pachinko1Operate, &s_Pachinko2Operate[17]},
    {PACHINKO2_R0 + 17, 12, Pachinko1Operate, &s_Pachinko2Operate[18]},
    {PACHINKO2_R0 + 18, 12, Pachinko1Operate, &s_Pachinko2Operate[19]},
    {PACHINKO2_R0 + 19, 12, Pachinko1Operate, &s_Pachinko2Operate[20]},
    {PACHINKO2_R0 + 20, 12, Pachinko1Operate, &s_Pachinko2Operate[21]},
    {PACHINKO2_R0 + 21, 12, Pachinko1Operate, &s_Pachinko2Operate[22]},
    {PACHINKO2_R0 + 22, SF_QUICK_CALL, PachinkoCheckWin, &s_Pachinko2Stand[0]}
};

int
SetupPachinko2(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,PACHINKO2,s_Pachinko2Stand);
        u->Health = 1;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_Pachinko2Stand);
    u->Attrib = &Pachinko2Attrib;
    u->StateEnd = s_Pachinko2Stand;
    u->Rot = 0;
    u->RotNum = 0;
    u->ID = PACHINKO2;

    sp->yvel = sp->zvel = 0;
    sp->lotag = PACHINKO2;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);
    RESET(sp->extra, SPRX_PLAYER_OR_ENEMY);

    return 0;
}

////////////////////////////////////////////////////////////////////
// PACHINKO MACHINE #3
////////////////////////////////////////////////////////////////////

ATTRIBUTE Pachinko3Attrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    0,                               // MaxWeapons;
    {0, 0, DIGI_TRASHLID, DIGI_TRASHLID, 0, 0,0,0,0,0}
};

#define PACHINKO3_RATE 120
#define PACHINKO3_R0 PACHINKO3

STATE s_Pachinko3Stand[] =
{
    {PACHINKO3_R0 + 0, PACHINKO3_RATE, NullAnimator, &s_Pachinko3Stand[0]}
};

ANIMATOR Pachinko3Operate;
STATE s_Pachinko3Operate[] =
{
    {PACHINKO3_R0 + 0, 12, Pachinko1Operate, &s_Pachinko3Operate[1]},
    {PACHINKO3_R0 + 1, 12, Pachinko1Operate, &s_Pachinko3Operate[2]},
    {PACHINKO3_R0 + 2, 12, Pachinko1Operate, &s_Pachinko3Operate[3]},
    {PACHINKO3_R0 + 3, 12, Pachinko1Operate, &s_Pachinko3Operate[4]},
    {PACHINKO3_R0 + 4, 12, Pachinko1Operate, &s_Pachinko3Operate[5]},
    {PACHINKO3_R0 + 5, 12, Pachinko1Operate, &s_Pachinko3Operate[6]},
    {PACHINKO3_R0 + 6, 12, Pachinko1Operate, &s_Pachinko3Operate[7]},
    {PACHINKO3_R0 + 7, 12, Pachinko1Operate, &s_Pachinko3Operate[8]},
    {PACHINKO3_R0 + 8, 12, Pachinko1Operate, &s_Pachinko3Operate[9]},
    {PACHINKO3_R0 + 9, 12, Pachinko1Operate, &s_Pachinko3Operate[10]},
    {PACHINKO3_R0 + 10, 12, Pachinko1Operate, &s_Pachinko3Operate[11]},
    {PACHINKO3_R0 + 11, 12, Pachinko1Operate, &s_Pachinko3Operate[12]},
    {PACHINKO3_R0 + 12, 12, Pachinko1Operate, &s_Pachinko3Operate[13]},
    {PACHINKO3_R0 + 13, 12, Pachinko1Operate, &s_Pachinko3Operate[14]},
    {PACHINKO3_R0 + 14, 12, Pachinko1Operate, &s_Pachinko3Operate[15]},
    {PACHINKO3_R0 + 15, 12, Pachinko1Operate, &s_Pachinko3Operate[16]},
    {PACHINKO3_R0 + 16, 12, Pachinko1Operate, &s_Pachinko3Operate[17]},
    {PACHINKO3_R0 + 17, 12, Pachinko1Operate, &s_Pachinko3Operate[18]},
    {PACHINKO3_R0 + 18, 12, Pachinko1Operate, &s_Pachinko3Operate[19]},
    {PACHINKO3_R0 + 19, 12, Pachinko1Operate, &s_Pachinko3Operate[20]},
    {PACHINKO3_R0 + 20, 12, Pachinko1Operate, &s_Pachinko3Operate[21]},
    {PACHINKO3_R0 + 21, 12, Pachinko1Operate, &s_Pachinko3Operate[22]},
    {PACHINKO3_R0 + 22, SF_QUICK_CALL, PachinkoCheckWin, &s_Pachinko3Stand[0]}
};

int
SetupPachinko3(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,PACHINKO3,s_Pachinko3Stand);
        u->Health = 1;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_Pachinko3Stand);
    u->Attrib = &Pachinko3Attrib;
    u->StateEnd = s_Pachinko3Stand;
    u->Rot = 0;
    u->RotNum = 0;
    u->ID = PACHINKO3;

    sp->yvel = sp->zvel = 0;
    sp->lotag = PACHINKO3;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);
    RESET(sp->extra, SPRX_PLAYER_OR_ENEMY);

    return 0;
}

////////////////////////////////////////////////////////////////////
// PACHINKO MACHINE #4
////////////////////////////////////////////////////////////////////

ATTRIBUTE Pachinko4Attrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    0,                               // MaxWeapons;
    {0, 0, DIGI_TRASHLID, DIGI_TRASHLID, 0, 0,0,0,0,0}
};

#define PACHINKO4_RATE 120
#define PACHINKO4_R0 PACHINKO4

STATE s_Pachinko4Stand[] =
{
    {PACHINKO4_R0 + 0, PACHINKO4_RATE, NullAnimator, &s_Pachinko4Stand[0]}
};

ANIMATOR Pachinko4Operate;
STATE s_Pachinko4Operate[] =
{
    {PACHINKO4_R0 + 0, 12, Pachinko1Operate, &s_Pachinko4Operate[1]},
    {PACHINKO4_R0 + 1, 12, Pachinko1Operate, &s_Pachinko4Operate[2]},
    {PACHINKO4_R0 + 2, 12, Pachinko1Operate, &s_Pachinko4Operate[3]},
    {PACHINKO4_R0 + 3, 12, Pachinko1Operate, &s_Pachinko4Operate[4]},
    {PACHINKO4_R0 + 4, 12, Pachinko1Operate, &s_Pachinko4Operate[5]},
    {PACHINKO4_R0 + 5, 12, Pachinko1Operate, &s_Pachinko4Operate[6]},
    {PACHINKO4_R0 + 6, 12, Pachinko1Operate, &s_Pachinko4Operate[7]},
    {PACHINKO4_R0 + 7, 12, Pachinko1Operate, &s_Pachinko4Operate[8]},
    {PACHINKO4_R0 + 8, 12, Pachinko1Operate, &s_Pachinko4Operate[9]},
    {PACHINKO4_R0 + 9, 12, Pachinko1Operate, &s_Pachinko4Operate[10]},
    {PACHINKO4_R0 + 10, 12, Pachinko1Operate, &s_Pachinko4Operate[11]},
    {PACHINKO4_R0 + 11, 12, Pachinko1Operate, &s_Pachinko4Operate[12]},
    {PACHINKO4_R0 + 12, 12, Pachinko1Operate, &s_Pachinko4Operate[13]},
    {PACHINKO4_R0 + 13, 12, Pachinko1Operate, &s_Pachinko4Operate[14]},
    {PACHINKO4_R0 + 14, 12, Pachinko1Operate, &s_Pachinko4Operate[15]},
    {PACHINKO4_R0 + 15, 12, Pachinko1Operate, &s_Pachinko4Operate[16]},
    {PACHINKO4_R0 + 16, 12, Pachinko1Operate, &s_Pachinko4Operate[17]},
    {PACHINKO4_R0 + 17, 12, Pachinko1Operate, &s_Pachinko4Operate[18]},
    {PACHINKO4_R0 + 18, 12, Pachinko1Operate, &s_Pachinko4Operate[19]},
    {PACHINKO4_R0 + 19, 12, Pachinko1Operate, &s_Pachinko4Operate[20]},
    {PACHINKO4_R0 + 20, 12, Pachinko1Operate, &s_Pachinko4Operate[21]},
    {PACHINKO4_R0 + 21, 12, Pachinko1Operate, &s_Pachinko4Operate[22]},
    {PACHINKO4_R0 + 22, SF_QUICK_CALL, PachinkoCheckWin, &s_Pachinko4Stand[0]}
};

int
SetupPachinko4(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,PACHINKO4,s_Pachinko4Stand);
        u->Health = 1;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_Pachinko4Stand);
    u->Attrib = &Pachinko4Attrib;
    u->StateEnd = s_Pachinko4Stand;
    u->Rot = 0;
    u->RotNum = 0;
    u->ID = PACHINKO4;

    sp->yvel = sp->zvel = 0;
    sp->lotag = PACHINKO4;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);
    RESET(sp->extra, SPRX_PLAYER_OR_ENEMY);

    return 0;
}

////////////////////////////////////////////////////////////////////////////////

ANIMATOR NullCarGirl;

ATTRIBUTE CarGirlAttrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    3,                               // MaxWeapons;
    {
        0, 0, DIGI_TOILETGIRLSCREAM,
        DIGI_TOILETGIRLPAIN, DIGI_TOILETGIRLSCREAM, 0,0,0,0,0
    }
};

//////////////////////
//
// CARGIRL STAND
//
//////////////////////
#define CARGIRL_RATE 60
ANIMATOR NullCarGirl,DoCarGirl;

STATE s_CarGirlStand[2] =
{
    {CARGIRL_R0 + 0, CARGIRL_RATE, DoCarGirl, &s_CarGirlStand[1]},
    {CARGIRL_R0 + 1, CARGIRL_RATE, DoCarGirl, &s_CarGirlStand[0]}
};

//////////////////////
//
// CARGIRL PAIN
//
//////////////////////

#define CARGIRL_PAIN_RATE 32
#define CARGIRL_PAIN_R0 CARGIRL_R0
ANIMATOR CarGirlPain;

STATE s_CarGirlPain[2] =
{
    {CARGIRL_PAIN_R0 + 0, CARGIRL_PAIN_RATE, CarGirlPain, &s_CarGirlPain[1]},
    {CARGIRL_PAIN_R0 + 0, 0|SF_QUICK_CALL, InitActorDecide, &s_CarGirlPain[0]}
};

//////////////////////
//
// CARGIRL UZI
//
//////////////////////

#define CARGIRL_UZI_RATE 8
#define CARGIRL_FIRE_R0 CARGIRL_R0 + 2
ANIMATOR InitEnemyUzi,CarGirlUzi;

STATE s_CarGirlUzi[16] =
{
    {CARGIRL_FIRE_R0 + 0, 240, CarGirlUzi, &s_CarGirlUzi[1]},
    {CARGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_CarGirlUzi[2]},
    {CARGIRL_FIRE_R0 + 1, CARGIRL_UZI_RATE, CarGirlUzi, &s_CarGirlUzi[3]},
    {CARGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_CarGirlUzi[4]},
    {CARGIRL_FIRE_R0 + 0, CARGIRL_UZI_RATE, CarGirlUzi, &s_CarGirlUzi[5]},
    {CARGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_CarGirlUzi[6]},
    {CARGIRL_FIRE_R0 + 1, CARGIRL_UZI_RATE, CarGirlUzi, &s_CarGirlUzi[7]},
    {CARGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_CarGirlUzi[8]},
    {CARGIRL_FIRE_R0 + 0, CARGIRL_UZI_RATE, CarGirlUzi, &s_CarGirlUzi[9]},
    {CARGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_CarGirlUzi[10]},
    {CARGIRL_FIRE_R0 + 1, CARGIRL_UZI_RATE, CarGirlUzi, &s_CarGirlUzi[11]},
    {CARGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_CarGirlUzi[12]},
    {CARGIRL_FIRE_R0 + 0, CARGIRL_UZI_RATE, CarGirlUzi, &s_CarGirlUzi[13]},
    {CARGIRL_FIRE_R0 + 0, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_CarGirlUzi[14]},
    {CARGIRL_FIRE_R0 + 1, CARGIRL_UZI_RATE, CarGirlUzi, &s_CarGirlUzi[15]},
    {CARGIRL_FIRE_R0 + 1, 0 | SF_QUICK_CALL, InitEnemyUzi, &s_CarGirlUzi[0]},
};

int
SetupCarGirl(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,CARGIRL_R0,s_CarGirlStand);
        u->Health = 60;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_CarGirlStand);
    u->Attrib = &CarGirlAttrib;
    u->StateEnd = s_CarGirlStand;
    u->Rot = 0;
    u->RotNum = 0;

    sp->xrepeat = 29;
    sp->yrepeat = 25;
    sp->xvel = sp->yvel = sp->zvel = 0;
    sp->lotag = CARGIRL_R0;
    u->FlagOwner = 0;
    u->ID = CARGIRL_R0;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);
    SET(sp->cstat, CSTAT_SPRITE_XFLIP);

    return 0;
}

int DoCarGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,SPRITEp_MID(u->tgt_sp),u->tgt_sp->sectnum);

    if (u->FlagOwner == 1)
    {
        if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
        {
            static int madhandle;

            if (!FX_SoundValidAndActive(madhandle))
            {
                short choose;
                choose = RANDOM_RANGE(1000);

                if (choose > 750)
                    madhandle = PlaySound(DIGI_LANI049,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else if (choose > 500)
                    madhandle = PlaySound(DIGI_LANI051,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else if (choose > 250)
                    madhandle = PlaySound(DIGI_LANI052,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else
                    madhandle = PlaySound(DIGI_LANI054,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            }
            ChangeState(SpriteNum,s_CarGirlUzi);
            u->WaitTics = SEC(3)+SEC(RANDOM_RANGE(2<<8)>>8);
            u->FlagOwner = 0;
        }
    }

    //(*u->ActorActionFunc) (SpriteNum);

    // stay on floor unless doing certain things
    if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING | SPR_CLIMBING))
    {
        KeepActorOnFloor(SpriteNum);
    }

    // take damage from environment
    DoActorSectorDamage(SpriteNum);
    sp->xvel = sp->yvel = sp->zvel = 0;

    return 0;
}

int NullCarGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,u->tgt_sp->z,u->tgt_sp->sectnum);

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if (u->FlagOwner != 1)
    {
    }
    else if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
    {
        static int madhandle;

        if (!FX_SoundValidAndActive(madhandle))
        {
            short choose;
            choose = RANDOM_RANGE(1000);

            if (choose > 750)
                madhandle = PlaySound(DIGI_LANI049,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 500)
                madhandle = PlaySound(DIGI_LANI051,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 250)
                madhandle = PlaySound(DIGI_LANI052,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else
                madhandle = PlaySound(DIGI_LANI054,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }
        ChangeState(SpriteNum,s_CarGirlUzi);
        u->WaitTics = SEC(3)+SEC(RANDOM_RANGE(2<<8)>>8);
        u->FlagOwner = 0;
    }

    return 0;
}

int CarGirlUzi(short SpriteNum)
{
    USERp u = User[SpriteNum];

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
    {
        u->WaitTics = RANDOM_RANGE(240)+120;
        ChangeState(SpriteNum,s_CarGirlStand);
        u->FlagOwner = 0;
    }

    return 0;
}

int CarGirlPain(short SpriteNum)
{
    USERp u = User[SpriteNum];

    NullCarGirl(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
        ChangeState(SpriteNum,s_CarGirlStand);

    return 0;
}

////////////////////////////////////////////////////////////////////////////////

ANIMATOR NullMechanicGirl;

ATTRIBUTE MechanicGirlAttrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    3,                               // MaxWeapons;
    {
        0, 0, DIGI_TOILETGIRLSCREAM,
        DIGI_TOILETGIRLPAIN, DIGI_TOILETGIRLSCREAM, 0,0,0,0,0
    }
};

//////////////////////
//
// MECHANICGIRL STAND
//
//////////////////////
#define MECHANICGIRL_RATE 60
ANIMATOR NullMechanicGirl,DoMechanicGirl;

STATE s_MechanicGirlStand[2] =
{
    {MECHANICGIRL_R0 + 0, MECHANICGIRL_RATE, DoMechanicGirl, &s_MechanicGirlStand[1]},
    {MECHANICGIRL_R0 + 1, MECHANICGIRL_RATE, DoMechanicGirl, &s_MechanicGirlStand[0]}
};

//////////////////////
//
// MECHANICGIRL PAIN
//
//////////////////////

#define MECHANICGIRL_PAIN_RATE 32
#define MECHANICGIRL_PAIN_R0 MECHANICGIRL_R0
ANIMATOR MechanicGirlPain;

STATE s_MechanicGirlPain[2] =
{
    {MECHANICGIRL_PAIN_R0 + 0, MECHANICGIRL_PAIN_RATE, MechanicGirlPain, &s_MechanicGirlPain[1]},
    {MECHANICGIRL_PAIN_R0 + 0, 0|SF_QUICK_CALL, InitActorDecide, &s_MechanicGirlPain[0]}
};

//////////////////////
//
// MECHANICGIRL DRILL
//
//////////////////////

#define MECHANICGIRL_DRILL_RATE 32
#define MECHANICGIRL_DRILL_R0 MECHANICGIRL_R0 + 2
ANIMATOR MechanicGirlDrill;

STATE s_MechanicGirlDrill[2] =
{
    {MECHANICGIRL_DRILL_R0 + 0, MECHANICGIRL_DRILL_RATE, MechanicGirlDrill, &s_MechanicGirlDrill[1]},
    {MECHANICGIRL_DRILL_R0 + 1, MECHANICGIRL_DRILL_RATE, MechanicGirlDrill, &s_MechanicGirlDrill[0]},
};

int
SetupMechanicGirl(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,MECHANICGIRL_R0,s_MechanicGirlStand);
        u->Health = 60;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_MechanicGirlStand);
    u->Attrib = &MechanicGirlAttrib;
    u->StateEnd = s_MechanicGirlStand;
    u->Rot = 0;
    u->RotNum = 0;

    sp->xrepeat = 27;
    sp->yrepeat = 26;
    sp->xvel = sp->yvel = sp->zvel = 0;
    sp->lotag = MECHANICGIRL_R0;
    u->FlagOwner = 0;
    u->ID = MECHANICGIRL_R0;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);

    return 0;
}

int DoMechanicGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,SPRITEp_MID(u->tgt_sp),u->tgt_sp->sectnum);

    if (u->FlagOwner == 1)
    {
        if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
        {
            static int madhandle;

            if (!FX_SoundValidAndActive(madhandle))
            {
                short choose;
                choose = RANDOM_RANGE(1000);

                if (choose > 750)
                    madhandle = PlaySound(DIGI_LANI073,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else if (choose > 500)
                    madhandle = PlaySound(DIGI_LANI075,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else if (choose > 250)
                    madhandle = PlaySound(DIGI_LANI077,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else
                    madhandle = PlaySound(DIGI_LANI079,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            }
            ChangeState(SpriteNum,s_MechanicGirlDrill);
            u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(2<<8)>>8);
            u->FlagOwner = 0;
        }
    }

    //(*u->ActorActionFunc) (SpriteNum);

    // stay on floor unless doing certain things
    if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING | SPR_CLIMBING))
    {
        KeepActorOnFloor(SpriteNum);
    }

    // take damage from environment
    DoActorSectorDamage(SpriteNum);
    sp->xvel = sp->yvel = sp->zvel = 0;

    return 0;
}

int NullMechanicGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,u->tgt_sp->z,u->tgt_sp->sectnum);

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if (u->FlagOwner != 1)
    {
    }
    else if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
    {
        static int madhandle;

        if (!FX_SoundValidAndActive(madhandle))
        {
            short choose;
            choose = RANDOM_RANGE(1000);

            if (choose > 750)
                madhandle = PlaySound(DIGI_LANI073,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 500)
                madhandle = PlaySound(DIGI_LANI075,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 250)
                madhandle = PlaySound(DIGI_LANI077,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else
                madhandle = PlaySound(DIGI_LANI079,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }
        ChangeState(SpriteNum,s_MechanicGirlDrill);
        u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(2<<8)>>8);
        u->FlagOwner = 0;
    }

    return 0;
}

int MechanicGirlDrill(short SpriteNum)
{
    USERp u = User[SpriteNum];

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
    {
        u->WaitTics = RANDOM_RANGE(240)+120;
        ChangeState(SpriteNum,s_MechanicGirlStand);
        u->FlagOwner = 0;
    }

    return 0;
}

int MechanicGirlPain(short SpriteNum)
{
    USERp u = User[SpriteNum];

    NullMechanicGirl(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
        ChangeState(SpriteNum,s_MechanicGirlStand);

    return 0;
}

////////////////////////////////////////////////////////////////////////////////

ANIMATOR NullSailorGirl;

ATTRIBUTE SailorGirlAttrib =
{
    {0, 0, 0, 0},                     // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    3,                               // MaxWeapons;
    {
        0, 0, DIGI_TOILETGIRLSCREAM,
        DIGI_TOILETGIRLPAIN, DIGI_TOILETGIRLSCREAM, 0,0,0,0,0
    }
};

//////////////////////
//
// SAILORGIRL STAND
//
//////////////////////
#define SAILORGIRL_RATE 60
ANIMATOR NullSailorGirl,DoSailorGirl;

STATE s_SailorGirlStand[2] =
{
    {SAILORGIRL_R0 + 0, SAILORGIRL_RATE, DoSailorGirl, &s_SailorGirlStand[1]},
    {SAILORGIRL_R0 + 1, SAILORGIRL_RATE, DoSailorGirl, &s_SailorGirlStand[0]}
};

//////////////////////
//
// SAILORGIRL PAIN
//
//////////////////////

#define SAILORGIRL_PAIN_RATE 32
#define SAILORGIRL_PAIN_R0 SAILORGIRL_R0
ANIMATOR SailorGirlPain;

STATE s_SailorGirlPain[2] =
{
    {SAILORGIRL_PAIN_R0 + 0, SAILORGIRL_PAIN_RATE, SailorGirlPain, &s_SailorGirlPain[1]},
    {SAILORGIRL_PAIN_R0 + 0, 0|SF_QUICK_CALL, InitActorDecide, &s_SailorGirlPain[0]}
};

//////////////////////
//
// SAILORGIRL UZI
//
//////////////////////

#define SAILORGIRL_UZI_RATE 128
#define SAILORGIRL_FIRE_R0 SAILORGIRL_R0 + 2
ANIMATOR InitEnemyUzi,SailorGirlThrow;

STATE s_SailorGirlThrow[] =
{
    {SAILORGIRL_FIRE_R0 + 0, SAILORGIRL_UZI_RATE, SailorGirlThrow, &s_SailorGirlThrow[0]},
};

short alreadythrew;

int
SetupSailorGirl(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,SAILORGIRL_R0,s_SailorGirlStand);
        u->Health = 60;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_SailorGirlStand);
    u->Attrib = &SailorGirlAttrib;
    u->StateEnd = s_SailorGirlStand;
    u->Rot = 0;
    u->RotNum = 0;

    sp->xrepeat = 28;
    sp->yrepeat = 26;
    sp->xvel = sp->yvel = sp->zvel = 0;
    sp->lotag = SAILORGIRL_R0;
    u->FlagOwner = 0;
    u->ID = SAILORGIRL_R0;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);
    alreadythrew = 0;

    return 0;
}

int DoSailorGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,SPRITEp_MID(u->tgt_sp),u->tgt_sp->sectnum);

    if (u->FlagOwner == 1)
    {
        if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
        {
            static int madhandle;

            if (!FX_SoundValidAndActive(madhandle))
            {
                short choose;
                choose = RANDOM_RANGE(1000);

                if (choose > 750 && alreadythrew < 3)
                {
                    ActorCoughItem(SpriteNum);
                    alreadythrew++;
                    madhandle = PlaySound(DIGI_LANI060,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                }
                else if (choose > 500)
                    madhandle = PlaySound(DIGI_LANI063,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else if (choose > 250)
                    madhandle = PlaySound(DIGI_LANI065,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else
                    madhandle = PlaySound(DIGI_LANI066,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            }
            ChangeState(SpriteNum,s_SailorGirlThrow);
            u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(3<<8)>>8);
            u->FlagOwner = 0;
        }
    }

    //(*u->ActorActionFunc) (SpriteNum);

    // stay on floor unless doing certain things
    if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING | SPR_CLIMBING))
    {
        KeepActorOnFloor(SpriteNum);
    }

    // take damage from environment
    DoActorSectorDamage(SpriteNum);
    sp->xvel = sp->yvel = sp->zvel = 0;

    return 0;
}

int NullSailorGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;
    static short alreadythrew = 0;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,u->tgt_sp->z,u->tgt_sp->sectnum);

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if (u->FlagOwner != 1)
    {
    }
    else if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
    {
        static int madhandle;

        if (!FX_SoundValidAndActive(madhandle))
        {
            short choose;
            choose = RANDOM_RANGE(1000);

            if (choose > 750 && alreadythrew < 3)
            {
                ActorCoughItem(SpriteNum);
                alreadythrew++;
                madhandle = PlaySound(DIGI_LANI060,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            }
            else if (choose > 500)
                madhandle = PlaySound(DIGI_LANI063,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 250)
                madhandle = PlaySound(DIGI_LANI065,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else
                madhandle = PlaySound(DIGI_LANI066,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }
        ChangeState(SpriteNum,s_SailorGirlThrow);
        u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(3<<8)>>8);
        u->FlagOwner = 0;
    }

    return 0;
}

int SailorGirlThrow(short SpriteNum)
{
    USERp u = User[SpriteNum];

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
    {
        u->WaitTics = RANDOM_RANGE(240)+120;
        ChangeState(SpriteNum,s_SailorGirlStand);
        u->FlagOwner = 0;
    }

    return 0;
}

int SailorGirlPain(short SpriteNum)
{
    USERp u = User[SpriteNum];

    NullSailorGirl(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
        ChangeState(SpriteNum,s_SailorGirlStand);

    return 0;
}

////////////////////////////////////////////////////////////////////////////////

ANIMATOR NullPruneGirl;

ATTRIBUTE PruneGirlAttrib =
{
    {450, 450, 450, 450},             // Speeds
    {0, 0, 0, 0},                     // Tic Adjusts
    3,                               // MaxWeapons;
    //{DIGI_PRUNECACKLE3, DIGI_PRUNECACKLE, DIGI_TOILETGIRLSCREAM,
    {
        0,0, DIGI_TOILETGIRLSCREAM,
        DIGI_TOILETGIRLPAIN, DIGI_TOILETGIRLSCREAM, 0,0,0,0,0
    }
};

//////////////////////
//
// PRUNEGIRL STAND
//
//////////////////////
#define PRUNEGIRL_RATE 60
ANIMATOR NullPruneGirl,DoPruneGirl;

STATE s_PruneGirlStand[2] =
{
    {PRUNEGIRL_R0 + 0, PRUNEGIRL_RATE, DoPruneGirl, &s_PruneGirlStand[1]},
    {PRUNEGIRL_R0 + 1, PRUNEGIRL_RATE, DoPruneGirl, &s_PruneGirlStand[0]}
};

//////////////////////
//
// PRUNEGIRL PAIN
//
//////////////////////

#define PRUNEGIRL_PAIN_RATE 32
#define PRUNEGIRL_PAIN_R0 PRUNEGIRL_R0
ANIMATOR PruneGirlPain;

STATE s_PruneGirlPain[2] =
{
    {PRUNEGIRL_PAIN_R0 + 0, PRUNEGIRL_PAIN_RATE, PruneGirlPain, &s_PruneGirlPain[1]},
    {PRUNEGIRL_PAIN_R0 + 0, 0|SF_QUICK_CALL, InitActorDecide, &s_PruneGirlPain[0]}
};

int
SetupPruneGirl(short SpriteNum)
{
    SPRITEp sp = &sprite[SpriteNum];
    USERp u;
    ANIMATOR DoActorDecide;

    if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE))
    {
        u = User[SpriteNum];
        ASSERT(u);
    }
    else
    {
        User[SpriteNum] = u = SpawnUser(SpriteNum,PRUNEGIRL_R0,s_PruneGirlStand);
        u->Health = 60;
    }

    EnemyDefaults(SpriteNum, NULL, NULL);

    ChangeState(SpriteNum,s_PruneGirlStand);
    u->Attrib = &PruneGirlAttrib;
    u->StateEnd = s_PruneGirlStand;
    u->Rot = 0;
    u->RotNum = 0;

    sp->xrepeat = 33;
    sp->yrepeat = 28;
    sp->xvel = sp->yvel = sp->zvel = 0;
    sp->lotag = PRUNEGIRL_R0;
    u->FlagOwner = 0;
    u->ID = PRUNEGIRL_R0;

    RESET(u->Flags, SPR_XFLIP_TOGGLE);

    return 0;
}

int DoPruneGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    static int madhandle, coyhandle;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,SPRITEp_MID(u->tgt_sp),u->tgt_sp->sectnum);

    if (u->FlagOwner == 1)
    {
        if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
        {
            if (!FX_SoundValidAndActive(madhandle))
            {
                short choose;
                choose = STD_RANDOM_RANGE(1000);

                if (choose > 750)
                    madhandle = PlaySound(DIGI_LANI089,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else if (choose > 500)
                    madhandle = PlaySound(DIGI_LANI091,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else if (choose > 250)
                    madhandle = PlaySound(DIGI_LANI093,&sp->x,&sp->y,&sp->z,v3df_dontpan);
                else
                    madhandle = PlaySound(DIGI_LANI095,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            }
            u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(3<<8)>>8);
            u->FlagOwner = 0;
        }
    }
    else
    {
        if (!FX_SoundValidAndActive(coyhandle))
        {
            short choose;
            choose = STD_RANDOM_RANGE(1000);

            if (choose > 990)
                coyhandle = PlaySound(DIGI_PRUNECACKLE,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 985)
                coyhandle = PlaySound(DIGI_PRUNECACKLE2,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 980)
                coyhandle = PlaySound(DIGI_PRUNECACKLE3,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 975)
                coyhandle = PlaySound(DIGI_LANI091,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }
    }

    //(*u->ActorActionFunc) (SpriteNum);

    // stay on floor unless doing certain things
    if (!TEST(u->Flags, SPR_JUMPING | SPR_FALLING | SPR_CLIMBING))
    {
        KeepActorOnFloor(SpriteNum);
    }

    // take damage from environment
    DoActorSectorDamage(SpriteNum);
    sp->xvel = sp->yvel = sp->zvel = 0;

    return 0;
}

int NullPruneGirl(short SpriteNum)
{
    USERp u = User[SpriteNum];
    SPRITEp sp = User[SpriteNum]->SpriteP;
    SWBOOL ICanSee = FALSE;

    DoActorPickClosePlayer(SpriteNum);
    ICanSee = FAFcansee(sp->x,sp->y,SPRITEp_MID(sp),sp->sectnum,u->tgt_sp->x,u->tgt_sp->y,u->tgt_sp->z,u->tgt_sp->sectnum);

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if (u->FlagOwner != 1)
    {
    }
    else if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee)
    {
        static int madhandle;

        if (!FX_SoundValidAndActive(madhandle))
        {
            short choose;
            choose = RANDOM_RANGE(1000);

            if (choose > 750)
                madhandle = PlaySound(DIGI_LANI089,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 500)
                madhandle = PlaySound(DIGI_LANI091,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else if (choose > 250)
                madhandle = PlaySound(DIGI_LANI093,&sp->x,&sp->y,&sp->z,v3df_dontpan);
            else
                madhandle = PlaySound(DIGI_LANI095,&sp->x,&sp->y,&sp->z,v3df_dontpan);
        }
        u->WaitTics = SEC(1)+SEC(RANDOM_RANGE(3<<8)>>8);
        u->FlagOwner = 0;
    }

    return 0;
}

int PruneGirlUzi(short SpriteNum)
{
    USERp u = User[SpriteNum];

    if (!TEST(u->Flags,SPR_CLIMBING))
        KeepActorOnFloor(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
    {
        u->WaitTics = RANDOM_RANGE(240)+120;
        ChangeState(SpriteNum,s_PruneGirlStand);
        u->FlagOwner = 0;
    }

    return 0;
}

int PruneGirlPain(short SpriteNum)
{
    USERp u = User[SpriteNum];

    NullPruneGirl(SpriteNum);

    if ((u->WaitTics -= ACTORMOVETICS) <= 0)
        ChangeState(SpriteNum,s_PruneGirlStand);

    return 0;
}

#include "saveable.h"

static saveable_code saveable_miscactr_code[] =
{
    SAVE_CODE(SetupToiletGirl),
    SAVE_CODE(DoToiletGirl),
    SAVE_CODE(NullToiletGirl),
    SAVE_CODE(ToiletGirlUzi),
    SAVE_CODE(ToiletGirlPain),

    SAVE_CODE(SetupWashGirl),
    SAVE_CODE(DoWashGirl),
    SAVE_CODE(NullWashGirl),
    SAVE_CODE(WashGirlUzi),
    SAVE_CODE(WashGirlPain),

    SAVE_CODE(SetupTrashCan),
    SAVE_CODE(DoTrashCan),
    SAVE_CODE(TrashCanPain),

    SAVE_CODE(SetupPachinkoLight),
    SAVE_CODE(PachinkoLightOperate),

    SAVE_CODE(SetupPachinko1),
    SAVE_CODE(SetupPachinko2),
    SAVE_CODE(SetupPachinko3),
    SAVE_CODE(SetupPachinko4),
    SAVE_CODE(PachinkoCheckWin),
    SAVE_CODE(Pachinko1Operate),

    SAVE_CODE(SetupCarGirl),
    SAVE_CODE(DoCarGirl),
    SAVE_CODE(NullCarGirl),
    SAVE_CODE(CarGirlUzi),
    SAVE_CODE(CarGirlPain),

    SAVE_CODE(SetupMechanicGirl),
    SAVE_CODE(DoMechanicGirl),
    SAVE_CODE(NullMechanicGirl),
    SAVE_CODE(MechanicGirlDrill),
    SAVE_CODE(MechanicGirlPain),

    SAVE_CODE(SetupSailorGirl),
    SAVE_CODE(DoSailorGirl),
    SAVE_CODE(NullSailorGirl),
    SAVE_CODE(SailorGirlThrow),
    SAVE_CODE(SailorGirlPain),

    SAVE_CODE(SetupPruneGirl),
    SAVE_CODE(DoPruneGirl),
    SAVE_CODE(NullPruneGirl),
    SAVE_CODE(PruneGirlUzi),
    SAVE_CODE(PruneGirlPain),
};

static saveable_data saveable_miscactr_data[] =
{
    SAVE_DATA(ToiletGirlAttrib),
    SAVE_DATA(WashGirlAttrib),
    SAVE_DATA(TrashCanAttrib),
    SAVE_DATA(PachinkoLightAttrib),
    SAVE_DATA(Pachinko1Attrib),
    SAVE_DATA(Pachinko2Attrib),
    SAVE_DATA(Pachinko3Attrib),
    SAVE_DATA(Pachinko4Attrib),
    SAVE_DATA(CarGirlAttrib),
    SAVE_DATA(MechanicGirlAttrib),
    SAVE_DATA(SailorGirlAttrib),
    SAVE_DATA(PruneGirlAttrib),

    SAVE_DATA(s_ToiletGirlStand),
    SAVE_DATA(s_ToiletGirlPain),
    SAVE_DATA(s_ToiletGirlUzi),
    SAVE_DATA(s_WashGirlStand),
    SAVE_DATA(s_WashGirlStandScrub),
    SAVE_DATA(s_WashGirlPain),
    SAVE_DATA(s_WashGirlUzi),
    SAVE_DATA(s_TrashCanStand),
    SAVE_DATA(s_TrashCanPain),
    SAVE_DATA(s_PachinkoLightStand),
    SAVE_DATA(s_PachinkoLightOperate),
    SAVE_DATA(s_Pachinko1Stand),
    SAVE_DATA(s_Pachinko1Operate),
    SAVE_DATA(s_Pachinko2Stand),
    SAVE_DATA(s_Pachinko2Operate),
    SAVE_DATA(s_Pachinko3Stand),
    SAVE_DATA(s_Pachinko3Operate),
    SAVE_DATA(s_Pachinko4Stand),
    SAVE_DATA(s_Pachinko4Operate),
    SAVE_DATA(s_CarGirlStand),
    SAVE_DATA(s_CarGirlPain),
    SAVE_DATA(s_CarGirlUzi),
    SAVE_DATA(s_MechanicGirlStand),
    SAVE_DATA(s_MechanicGirlPain),
    SAVE_DATA(s_MechanicGirlDrill),
    SAVE_DATA(s_SailorGirlStand),
    SAVE_DATA(s_SailorGirlPain),
    SAVE_DATA(s_SailorGirlThrow),
    SAVE_DATA(s_PruneGirlStand),
    SAVE_DATA(s_PruneGirlPain)
};

saveable_module saveable_miscactr =
{
    // code
    saveable_miscactr_code,
    SIZ(saveable_miscactr_code),

    // data
    saveable_miscactr_data,
    SIZ(saveable_miscactr_data)
};


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 "panel.h"
//#include "keys.h"
#include "tags.h"
#include "sector.h"
#include "ai.h"
#include "player.h"
#include "game.h"

void ScaleSectorObject(SECTOR_OBJECTp);

short
DoSectorObjectSetScale(short match)
{
    SECTOR_OBJECTp sop;

    for (sop = SectorObject; sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++)
    {
        if (SO_EMPTY(sop))
            continue;

        if (sop->match_event == match)
        {
            SET(sop->flags, SOBJ_DYNAMIC);
            sop->PreMoveAnimator = ScaleSectorObject;

            switch (sop->scale_active_type)
            {
            case SO_SCALE_RANDOM_POINT:
                if (sop->scale_type == SO_SCALE_HOLD || sop->scale_type == SO_SCALE_NONE)
                {
                    // if holding start it up
                    sop->scale_type = sop->scale_active_type;
                }
                else
                {
                    // if moving set to hold
                    sop->scale_type = SO_SCALE_HOLD;
                }
                break;

            case SO_SCALE_DEST:

                sop->scale_type = sop->scale_active_type;

                if (sop->scale_dist == sop->scale_dist_max)
                {
                    // make it negative
                    if (sop->scale_speed > 0)
                        sop->scale_speed = -sop->scale_speed;
                }
                else
                {
                    // make it positive
                    if (sop->scale_speed < 0)
                        sop->scale_speed = -sop->scale_speed;
                }
                break;

            case SO_SCALE_RANDOM:
            case SO_SCALE_CYCLE:
                if (sop->scale_type == SO_SCALE_HOLD)
                {
                    // if holding start it up
                    sop->scale_type = sop->scale_active_type;
                }
                else
                {
                    // if moving set to hold
                    sop->scale_type = SO_SCALE_HOLD;
                }
                break;
            }
        }
    }
    return 0;
}

short
DoSOevent(short match, short state)
{
    SECTOR_OBJECTp sop;
    SPRITEp me_sp;
    short vel_adj=0, spin_adj=0;

    for (sop = SectorObject; sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++)
    {
        if (SO_EMPTY(sop))
            continue;

        if (sop->match_event == match)
        {
            if (TEST(sop->flags, SOBJ_WAIT_FOR_EVENT))
            {
                if (sop->save_vel > 0 || sop->save_spin_speed > 0)
                {
                    RESET(sop->flags, SOBJ_WAIT_FOR_EVENT);
                    sop->vel = sop->save_vel;
                    sop->spin_speed = sop->save_spin_speed;
                }
            }

            if (sop->match_event_sprite == -1)
                continue;

            me_sp = &sprite[sop->match_event_sprite];

            // toggle
            if (state == -1)
            {
                if (TEST_BOOL3(me_sp))
                {
                    RESET_BOOL3(me_sp);
                    state = OFF;
                }
                else
                {
                    SET_BOOL3(me_sp);
                    state = ON;
                }
            }

            if (state == ON)
            {
                spin_adj = (int)SP_TAG3(me_sp);
                vel_adj = SP_TAG7(me_sp);
            }
            else if (state == OFF)
            {
                spin_adj = -(int)SP_TAG3(me_sp);
                vel_adj = -SP_TAG7(me_sp);
            }

            sop->spin_speed += spin_adj;

            if (TEST_BOOL1(me_sp))
                sop->vel_tgt += vel_adj;
            else
                sop->vel += vel_adj;

            if (TEST_BOOL2(me_sp))
            {
                sop->dir *= -1;
            }
        }
    }
    return 0;
}

//
// SCALING - PreAnimator
//

void ScaleSectorObject(SECTOR_OBJECTp sop)
{
    switch (sop->scale_type)
    {
    case SO_SCALE_NONE:
        break;

    case SO_SCALE_HOLD:
        break;

    // to dest
    case SO_SCALE_DEST:
        sop->scale_dist += sop->scale_speed;

        if (sop->scale_dist > sop->scale_dist_max)
        {
            sop->scale_dist = sop->scale_dist_max;
            sop->scale_type = SO_SCALE_HOLD;
        }
        else if (sop->scale_dist < sop->scale_dist_min)
        {
            sop->scale_dist = sop->scale_dist_min;
            sop->scale_type = SO_SCALE_HOLD;
        }

        break;

    // random direction change
    case SO_SCALE_RANDOM:

        sop->scale_dist += sop->scale_speed;
        if (sop->scale_dist > sop->scale_dist_max)
        {
            sop->scale_speed *= -1;
            sop->scale_dist = sop->scale_dist_max;
        }
        else if (sop->scale_dist < sop->scale_dist_min)
        {
            sop->scale_speed *= -1;
            sop->scale_dist = sop->scale_dist_min;
        }

        if (RANDOM_P2(1024) < sop->scale_rand_freq<<3)
        {
            sop->scale_speed *= -1;
        }

        break;

    // cycle through max and min
    case SO_SCALE_CYCLE:
        sop->scale_dist += sop->scale_speed;

        if (sop->scale_dist > sop->scale_dist_max)
        {
            sop->scale_speed *= -1;
            sop->scale_dist = sop->scale_dist_max;
        }
        else if (sop->scale_dist < sop->scale_dist_min)
        {
            sop->scale_speed *= -1;
            sop->scale_dist = sop->scale_dist_min;
        }
        break;
    }
}

void ScaleRandomPoint(SECTOR_OBJECTp sop, short k, short ang, int x, int y, int *dx, int *dy)
{
    int xmul,ymul;

    sop->scale_point_dist[k] += sop->scale_point_speed[k];
    if (sop->scale_point_dist[k] > sop->scale_point_dist_max)
    {
        sop->scale_point_speed[k] *= -1;
        sop->scale_point_dist[k] = sop->scale_point_dist_max;
    }
    else if (sop->scale_point_dist[k] < sop->scale_point_dist_min)
    {
        sop->scale_point_speed[k] *= -1;
        sop->scale_point_dist[k] = sop->scale_point_dist_min;
    }

    if (RANDOM_P2(1024) < sop->scale_point_rand_freq)
    {
        sop->scale_point_speed[k] *= -1;
    }

    // change up speed at random
    if (RANDOM_P2(1024) < (sop->scale_point_rand_freq/2))
    {
        //sop->scale_point_speed[k] = SCALE_POINT_SPEED;
        short half = sop->scale_point_base_speed/2;
        short quart = sop->scale_point_base_speed/4;
        sop->scale_point_speed[k] = sop->scale_point_base_speed + (RANDOM_RANGE(half) - quart);
    }

    xmul = (sop->scale_point_dist[k] * sop->scale_x_mult)>>8;
    ymul = (sop->scale_point_dist[k] * sop->scale_y_mult)>>8;

    *dx = x + ((xmul * sintable[NORM_ANGLE(ang+512)]) >> 14);
    *dy = y + ((ymul * sintable[ang]) >> 14);
}

//
// Morph point - move point around
//

void
MorphTornado(SECTOR_OBJECTp sop)
{
    int mx, my;
    int ceilingz;
    int floorz;
    SECTORp *sectp;
    int j;
    int x,y,sx,sy;

    // z direction
    ASSERT(sop->op_main_sector >= 0);
    sop->morph_z += Z(sop->morph_z_speed);

    // move vector
    if (sop->morph_wall_point < 0)
        return;

    // place at correct x,y offset from center
    x = sop->xmid - sop->morph_xoff;
    y = sop->ymid - sop->morph_yoff;

    sx = x;
    sy = y;

    // move it from last x,y
    mx = x + (((sop->morph_speed) * sintable[NORM_ANGLE(sop->morph_ang+512)]) >> 14);
    my = y + (((sop->morph_speed) * sintable[sop->morph_ang]) >> 14);

    // bound check radius
    if (ksqrt(SQ(sop->xmid - mx) + SQ(sop->ymid - my)) > sop->morph_dist_max + sop->scale_dist)
    {
        // find angle
        sop->morph_ang = NORM_ANGLE(getangle(mx - sop->xmid, my - sop->ymid));
        // reverse angle
        sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024);

        // move back some from last point
        mx = sx + (((sop->morph_speed*2) * sintable[NORM_ANGLE(sop->morph_ang+512)]) >> 14);
        my = sy + (((sop->morph_speed*2) * sintable[sop->morph_ang]) >> 14);

        sop->morph_xoff = sop->xmid - mx;
        sop->morph_yoff = sop->ymid - my;
    }

    // save x,y back as offset info
    sop->morph_xoff = sop->xmid - mx;
    sop->morph_yoff = sop->ymid - my;

    if ((RANDOM_P2(1024<<4)>>4) < sop->morph_rand_freq)
        sop->morph_ang = RANDOM_P2(2048);

    // move it x,y
    dragpoint(sop->morph_wall_point, mx, my, 0);

    // bound the Z
    ceilingz = sector[sop->op_main_sector].ceilingz;
    floorz = sector[sop->op_main_sector].floorz;

    for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
    {
        if (SectUser[*sectp - sector] &&
            TEST(SectUser[*sectp - sector]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
        {
#define TOR_LOW (floorz)
            if (sop->morph_z > TOR_LOW)
            {
                sop->morph_z_speed *= -1;
                sop->morph_z = TOR_LOW;
            }
            else if (sop->morph_z < ceilingz)
            {
                sop->morph_z_speed *= -1;
                sop->morph_z = ceilingz;
            }

            alignceilslope(*sectp - sector, mx, my, sop->morph_z);
        }
    }
}

// moves center point around and aligns slope
void
MorphFloor(SECTOR_OBJECTp sop)
{
    int mx, my;
    int floorz;
    SECTORp *sectp;
    int j;
    int x,y;

    // z direction
    ASSERT(sop->op_main_sector >= 0);
    sop->morph_z -= Z(sop->morph_z_speed);

    // move vector
    if (sop->morph_wall_point < 0)
        return;

    // place at correct x,y offset from center
    x = sop->xmid - sop->morph_xoff;
    y = sop->ymid - sop->morph_yoff;

    // move it from last x,y
    mx = x + (((sop->morph_speed) * sintable[NORM_ANGLE(sop->morph_ang+512)]) >> 14);
    my = y + (((sop->morph_speed) * sintable[sop->morph_ang]) >> 14);

    // save x,y back as offset info
    sop->morph_xoff = sop->xmid - mx;
    sop->morph_yoff = sop->ymid - my;

    // bound check radius
    if (Distance(sop->xmid, sop->ymid, mx, my) > sop->morph_dist_max)
    {
        // go in the other direction
        //sop->morph_speed *= -1;
        sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024);

        // back it up and save it off
        mx = x + (((sop->morph_speed) * sintable[NORM_ANGLE(sop->morph_ang+512)]) >> 14);
        my = y + (((sop->morph_speed) * sintable[sop->morph_ang]) >> 14);
        sop->morph_xoff = sop->xmid - mx;
        sop->morph_yoff = sop->ymid - my;

        // turn it all the way around and then do a random -512 to 512 from there
        //sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024 + (RANDOM_P2(1024) - 512));
    }

    if ((RANDOM_P2(1024<<4)>>4) < sop->morph_rand_freq)
        sop->morph_ang = RANDOM_P2(2048);

    // move x,y point "just like in build"
    dragpoint(sop->morph_wall_point, mx, my, 0);

    // bound the Z
    floorz = sector[sop->op_main_sector].floorz;

#define MORPH_FLOOR_ZRANGE Z(300)

    if (sop->morph_z > MORPH_FLOOR_ZRANGE)
    {
        sop->morph_z = MORPH_FLOOR_ZRANGE;
        //sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024);
        sop->morph_z_speed *= -1;
    }
    else if (sop->morph_z < -MORPH_FLOOR_ZRANGE)
    {
        sop->morph_z = -MORPH_FLOOR_ZRANGE;
        //sop->morph_ang = NORM_ANGLE(sop->morph_ang + 1024);
        sop->morph_z_speed *= -1;
    }

    for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
    {
        if (SectUser[*sectp - sector] &&
            TEST(SectUser[*sectp - sector]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
        {
            alignflorslope(*sectp - sector, mx, my, floorz + sop->morph_z);
        }
    }
}

void
SOBJ_AlignFloorToPoint(SECTOR_OBJECTp sop, int x, int y, int z)
{
    SECTORp *sectp;
    int j;

    for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
    {
        if (SectUser[*sectp - sector] &&
            TEST(SectUser[*sectp - sector]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
        {
            alignflorslope(*sectp - sector, x, y, z);
        }
    }
}

void
SOBJ_AlignCeilingToPoint(SECTOR_OBJECTp sop, int x, int y, int z)
{
    SECTORp *sectp;
    int j;

    for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
    {
        if (SectUser[*sectp - sector] &&
            TEST(SectUser[*sectp - sector]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
        {
            alignceilslope(*sectp - sector, x, y, z);
        }
    }
}

void
SOBJ_AlignFloorCeilingToPoint(SECTOR_OBJECTp sop, int x, int y, int z)
{
    SECTORp *sectp;
    int j;

    for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
    {
        if (SectUser[*sectp - sector] &&
            TEST(SectUser[*sectp - sector]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
        {
            alignflorslope(*sectp - sector, x, y, z);
            alignceilslope(*sectp - sector, x, y, z);
        }
    }
}

// moves center point around and aligns slope
void
SpikeFloor(SECTOR_OBJECTp sop)
{
    int mx, my;
    int floorz;
    int x,y;

    // z direction
    ASSERT(sop->op_main_sector >= 0);
    sop->morph_z -= Z(sop->morph_z_speed);

    // move vector
    if (sop->morph_wall_point < 0)
        return;

    // place at correct x,y offset from center
    x = sop->xmid - sop->morph_xoff;
    y = sop->ymid - sop->morph_yoff;

    // move it from last x,y
    mx = x;
    my = y;

    // bound the Z
    floorz = sector[sop->op_main_sector].floorz;

#define MORPH_FLOOR_ZRANGE Z(300)

    if (sop->morph_z > MORPH_FLOOR_ZRANGE)
    {
        sop->morph_z = MORPH_FLOOR_ZRANGE;
        sop->morph_z_speed *= -1;
    }
    else if (sop->morph_z < -MORPH_FLOOR_ZRANGE)
    {
        sop->morph_z = -MORPH_FLOOR_ZRANGE;
        sop->morph_z_speed *= -1;
    }

    SOBJ_AlignFloorToPoint(sop, mx, my, floorz + sop->morph_z);

#if 0
    SECTORp *sectp;
    int j;
    for (sectp = sop->sectp, j = 0; *sectp; sectp++, j++)
    {
        if (SectUser[*sectp - sector] &&
            TEST(SectUser[*sectp - sector]->flags, SECTFU_SO_SLOPE_CEILING_TO_POINT))
        {
            alignflorslope(*sectp - sector, mx, my, floorz + sop->morph_z);
        }
    }
#endif
}

#include "saveable.h"

static saveable_code saveable_morph_code[] =
{
    SAVE_CODE(DoSectorObjectSetScale),
    SAVE_CODE(DoSOevent),
    SAVE_CODE(ScaleSectorObject),
    SAVE_CODE(ScaleRandomPoint),
    SAVE_CODE(MorphTornado),
    SAVE_CODE(MorphFloor),
    SAVE_CODE(SOBJ_AlignFloorToPoint),
    SAVE_CODE(SOBJ_AlignCeilingToPoint),
    SAVE_CODE(SOBJ_AlignFloorCeilingToPoint),
    SAVE_CODE(SpikeFloor),
};

saveable_module saveable_morph =
{
    // code
    saveable_morph_code,
    SIZ(saveable_morph_code),

    // data
    NULL,0
};


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 TYPES_H

#define TYPES_H

#include "compat.h"

#define OFF     0
#define ON     (!OFF)

typedef unsigned char SWBOOL;

/*
===========================
=
= FAST calculations
=
===========================
*/

// For fast DIVision of integers

#define DIV2(x)  ((x) >> 1)
#define DIV4(x)  ((x) >> 2)
#define DIV8(x)  ((x) >> 3)
#define DIV16(x) ((x) >> 4)
#define DIV32(x) ((x) >> 5)
#define DIV64(x) ((x) >> 6)
#define DIV128(x) ((x) >> 7)
#define DIV256(x) ((x) >> 8)

// Constants used in fast mods

#define C_MOD2   1
#define C_MOD4   3
#define C_MOD8   7
#define C_MOD16  15
#define C_MOD32  31
#define C_MOD64  63
#define C_MOD128 127
#define C_MOD256 255

// Fast mods of select 2 power numbers

#define MOD2(x) ((x) & C_MOD2)
#define MOD4(x) ((x) & C_MOD4)
#define MOD8(x) ((x) & C_MOD8)
#define MOD16(x) ((x) & C_MOD16)
#define MOD32(x) ((x) & C_MOD32)
#define MOD64(x) ((x) & C_MOD64)
#define MOD128(x) ((x) & C_MOD128)
#define MOD256(x) ((x) & C_MOD256)

// Fast mods of any power of 2

#define MOD_P2(number,modby)  ((number) & ((modby)-1))

// Truncates to select 2 power numbers

#define TRUNC2(x) ((x) & ~C_MOD2)
#define TRUNC4(x) ((x) & ~C_MOD4)
#define TRUNC8(x) ((x) & ~C_MOD8)
#define TRUNC16(x) ((x) & ~C_MOD16)
#define TRUNC32(x) ((x) & ~C_MOD32)
#define TRUNC64(x) ((x) & ~C_MOD64)
#define TRUNC128(x) ((x) & ~C_MOD128)
#define TRUNC256(x) ((x) & ~C_MOD256)

#define POWER2_TRUNC(number,truncby) ((number) & ~((truncby)-1))

// moves value to closest power of 2 pixel boundry

#define BOUND_2PIX(x) ( TRUNC2((x) + MOD2(x)) )
#define BOUND_4PIX(x) ( TRUNC4((x) + MOD4(x)) )
#define BOUND_8PIX(x) ( TRUNC8((x) + MOD8(x)) )
#define BOUND_16PIX(x) ( TRUNC16((x) + MOD16(x)) )
#define BOUND_32PIX(x) ( TRUNC32((x) + MOD32(x)) )
#define BOUND_64PIX(x) ( TRUNC64((x) + MOD64(x)) )
#define BOUND_128PIX(x) ( TRUNC128((x) + MOD128(x)) )
#define BOUND_256PIX(x) ( TRUNC256((x) + MOD256(x)) )

#define BOUND_POWER2_PIX(x,bound) ( POWER2_TRUNC((x,bound) + POWER2_MOD(x,bound)) )

// A few muls with shifts and adds
// probably not needed with good compiler
#define MUL2(x) ((x)*2)
#define MUL3(x) (((x)<<1) + (x))
#define MUL5(x) (((x)<<2) + (x))
#define MUL6(x) (((x)<<2) + (x) + (x))
#define MUL7(x) (((x)<<2) + (x) + (x) + (x))
#define MUL8(x) ((x)*8)
#define MUL9(x) (((x)<<3) + (x))
#define MUL10(x) (((x)<<3) + (x) + (x))
#define MUL11(x) (((x)<<3) + (x) + (x) + (x))
#define MUL12(x) (((x)<<3) + ((x)<<2))
#define MUL13(x) (((x)<<3) + ((x)<<2) + (x))
#define MUL14(x) (((x)<<3) + ((x)<<2) + (x) + (x))
#define MUL15(x) (((x)<<3) + ((x)<<2) + (x) + (x) + (x))
#define MUL16(x) ((x)*16)

/*
===========================
=
= Bit manipulation
=
===========================
*/

#define TEST(flags,mask) ((flags) & (mask))
#define SET(flags,mask) ((flags) |= (mask))
#define RESET(flags,mask) ((flags) &= ~(mask))
#define FLIP(flags,mask) ((flags) ^= (mask))

// mask definitions

#define BIT(shift)     (1<<(shift))

/*
===========================
=
= Miscellaneous
=
===========================
*/

//#define ABS(num) ((num) < 0 ? -(num) : (num))

#define BETWEEN(x,low,high) (((x) >= (low)) && ((x) <= (high)))

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

//Be careful when changing this file - it is parsed by Editart and Build.
#define ALPHABET 85
#define MENU_MAIN 295
#define MENU_OPTION 296
#define MENU_WHICH 297
#define MENU_CURSOR 298
#define DART1 2000
#define DART2 2001
#define DART3 2002
#define DART4 2003
#define DART 2004
#define FIRE1 2005
#define FIRE2 2006
#define FIRE3 2007
#define FIRE4 2008
#define FIRE5 2009
#define FIREBALL1 2010
#define FIREBALL2 2011
#define FIREBALL3 2012
#define FIREBALL4 2013
#define FLAMES1 2014
#define FLAMES2 2015
#define FLAMES3 2016
#define FLAMES4 2017
#define FLAMES5 2018
#define GAS1 2019
#define GAS2 2020
#define GAS3 2021
#define GAS4 2022
#define GAS5 2023
#define GAS6 2024
#define GAS7 2025
#define GASCLOUD1 2026
#define GASCLOUD2 2027
#define GASCLOUD3 2028
#define GASCLOUD4 2029
#define GASCLOUD5 2030
#define GASCLOUD6 2031
#define GASCLOUD7 2032
#define GASCLOUD8 2033
#define GASCLOUD9 2034
#define LIGHT1 2035
#define LIGHT2 2036
#define LIGHT3 2037
#define LIGHT4 2038
#define LIGHT5 2039
#define LIGHT6 2040
#define ELECTRO1 2041
#define ELECTRO2 2042
#define ELECTRO3 2043
#define RIFLE1 2044
#define RIFLE2 2045
#define RIFLE3 2046
#define DONTUSE_EXTRA 2047
#define RIFLE4 2048
#define CARTRIGE3 2053
#define STATUE1 2054
#define STATUE2 2055
#define STATUE3 2056
#define STATUE4 2057
#define SWORD3 2065
#define SWORD4 2066
#define SWORD1 2067
#define SWORD2 2068
#define SWORD5 2069
#define BLACK___ 2306
#define FragBarErase 2375
#define FragBarErase2 2376