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 NAMES2_H
#define NAMES2_H

#include "names.h"

// Rotation info

//      4
//    5   3
//  6       2
//    7   1
//      0

enum STAT_ENUMS
{
    STAT_DEFAULT=               0,
    STAT_MISC=                  1,

#define STAT_SKIP2_START    2
    STAT_ENEMY=                 2,
    STAT_DEAD_ACTOR=            3, //misc actor stuff - dead guys etc
    STAT_MISSILE=               4,
    STAT_SHRAP=                 5,
#define STAT_SKIP2_END          5
#define STAT_SKIP2_INTERP_END   5

#define STAT_SKIP4_START    6
    STAT_SKIP4=                 6,
    STAT_MISSILE_SKIP4=         7,
    STAT_MINE_STUCK=                  8, //solely for mines
    STAT_ENEMY_SKIP4=           9,
#define STAT_SKIP4_INTERP_END   9

    STAT_ITEM=                  10,
#define STAT_SKIP4_END          10

    STAT_FAF_COPY,
    STAT_MAX=20,  // everything below here can move
    STAT_PLAYER0,
    STAT_PLAYER1,
    STAT_PLAYER2,
    STAT_PLAYER3,

    STAT_PLAYER4,
    STAT_PLAYER5,
    STAT_PLAYER6,
    STAT_PLAYER7,
    STAT_PLAYER_UNDER0,

    STAT_PLAYER_UNDER1,
    STAT_PLAYER_UNDER2,
    STAT_PLAYER_UNDER3,
    STAT_PLAYER_UNDER4,
    STAT_PLAYER_UNDER5,

    STAT_PLAYER_UNDER6,
    STAT_PLAYER_UNDER7,
    STAT_GENERIC_QUEUE,
    STAT_OBJECT_SPRITE,   // sprites that move with objects
    STAT_WALLBLOOD_QUEUE,
    STAT_FLOORBLOOD_QUEUE,
    STAT_NO_STATE,        // sprites that don't need state control
    STAT_STATIC_FIRE,
    STAT_STAR_QUEUE,
    STAT_HOLE_QUEUE,
    STAT_BREAKABLE,
    STAT_SPRITE_HIT_MATCH, // TAG_SPRITE_HIT_MATCH
//
// Everything from here down does not get drawn
//
    STAT_DONT_DRAW,
    STAT_SUICIDE,
    STAT_DIVE_AREA,
    STAT_UNDERWATER,
    STAT_UNDERWATER2,

    STAT_CEILING_FLOOR_PIC_OVERRIDE,
    STAT_CLIMB_MARKER,
    STAT_ALL,
    STAT_SO_SHOOT_POINT,  // operational SO shooting point
    STAT_SPAWN_TRIGGER,   // triggers spawn sprites
    STAT_TRAP,            // triggered traps - spear/fireball etc
    STAT_TRIGGER,         // attempt to replace tagging sectors - use ST1 sprites
    STAT_DEMO_CAMERA,     // demo camera placement
    STAT_FAF,             // floor above floor stat
    STAT_SO_SP_CHILD,
    STAT_WARP,
    STAT_WARP_COPY_SPRITE1,

    STAT_WARP_COPY_SPRITE2,
    STAT_SOUND_SPOT,
    STAT_STOP_SOUND_SPOT,
    STAT_SPAWN_SPOT,
    STAT_AMBIENT,
    STAT_ECHO,
    STAT_VATOR,
    STAT_ROTATOR,
    STAT_ROTATOR_PIVOT,
    STAT_SLIDOR,
    STAT_FLOOR_SLOPE_DONT_DRAW,

    STAT_EXPLODING_CEIL_FLOOR,
    STAT_COPY_SOURCE,
    STAT_COPY_DEST,
    STAT_WALL_MOVE,
    STAT_WALL_MOVE_CANSEE,

    STAT_SPAWN_ITEMS,
    STAT_DELETE_SPRITE,
    STAT_SPIKE,
    STAT_LIGHTING,
    STAT_LIGHTING_DIFFUSE,
    STAT_WALL_DONT_MOVE_UPPER,
    STAT_WALL_DONT_MOVE_LOWER,
    STAT_FLOOR_PAN,
    STAT_CEILING_PAN,
    STAT_WALL_PAN,
    STAT_NO_RIDE,
    STAT_QUAKE_SPOT,
    STAT_QUAKE_ON,
    STAT_VIS_ON,
    STAT_CHANGOR,

    STAT_TRACK=200,
    STAT_ST1=500,
    STAT_QUICK_JUMP,
    STAT_QUICK_JUMP_DOWN,
    STAT_QUICK_SUPER_JUMP,
    STAT_QUICK_SCAN,
    STAT_QUICK_EXIT,
    STAT_QUICK_LADDER,
    STAT_QUICK_OPERATE,
    STAT_QUICK_DUCK,
    STAT_QUICK_DEFEND
};

// multi player start
#define STAT_MULTI_START    600
#define STAT_MULTI_START1   601
#define STAT_MULTI_START2   602
#define STAT_MULTI_START3   603
#define STAT_MULTI_START4   604
#define STAT_MULTI_START5   605
#define STAT_MULTI_START6   606
#define STAT_MULTI_START7   607

#define STAT_CO_OP_START    610
#define STAT_CO_OP_START1   611
#define STAT_CO_OP_START2   612
#define STAT_CO_OP_START3   613
#define STAT_CO_OP_START4   614
#define STAT_CO_OP_START5   615
#define STAT_CO_OP_START6   616
#define STAT_CO_OP_START7   617

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

#define SWITCH_ON   562
#define SWITCH_OFF  561

#define TRACK_SPRITE  1900 //start of track sprites
#define ST1 2307
#define ST2 2308
#define ST_QUICK_JUMP 2309
#define ST_QUICK_JUMP_DOWN 2310
#define ST_QUICK_SUPER_JUMP 2311
#define ST_QUICK_SCAN 2312
#define ST_QUICK_EXIT 2313
#define ST_QUICK_OPERATE 2314
#define ST_QUICK_DUCK 2315
#define ST_QUICK_DEFEND 2316

//////////////////////
//
// TIMERS
//
//////////////////////

#define TICS_PER_SEC 120

#define FLY_INVENTORY_TIME 30
#define CLOAK_INVENTORY_TIME 30
#define ENVIRON_SUIT_INVENTORY_TIME 30

#define DAMAGE_TIME (1 * TICS_PER_SEC)

//////////////////////
//
// BLADES
//
//////////////////////

#define BLADE1  360
#define BLADE2  361
#define BLADE3  362

#define HORIZ_BLADES BLADE1 : BLADE2 : BLADE3

//////////////////////
//
// WEAPON RELATED
//
//////////////////////

#define ICON_STAR  1793

#define ICON_UZI   1797
#define ICON_UZIFLOOR 1807
#define ICON_LG_UZI_AMMO  1799

#define ICON_HEART      1824
#define ICON_HEART_LG_AMMO 1820

#define ICON_GUARD_HEAD 1814
#define ICON_FIREBALL_LG_AMMO 3035

#define NAPALM_MIN_AMMO 10
#define RING_MIN_AMMO 30

#define ICON_ROCKET      1843
#define ICON_SHOTGUN     1794
#define ICON_LG_ROCKET 1796
#define ICON_LG_SHOTSHELL 1823
#define ICON_AUTORIOT 1822

#define ICON_MICRO_GUN 1818
#define ICON_MICRO_BATTERY 1800

#define ICON_GRENADE_LAUNCHER 1817
#define ICON_LG_GRENADE 1831

#define ICON_LG_MINE 1842

#define ICON_RAIL_GUN 1811
#define ICON_RAIL_AMMO 1812

// not used now
#define ICON_SPELL     1880
#define ICON_ELECTRO   1822

#define ICON_EXPLOSIVE_BOX 1801
#define ICON_ENVIRON_SUIT   1837
#define ICON_FLY      1782
#define ICON_CLOAK    1804
#define ICON_NIGHT_VISION 3031
#define ICON_NAPALM      3046
#define ICON_RING        3050
#define ICON_GOROAMMO    3035
#define ICON_HEARTAMMO   1820
#define ICON_RINGAMMO    3054
#define ICON_NAPALMAMMO  3058
#define ICON_GRENADE     3059
#define ICON_OXYGEN      1800
#define ICON_ARMOR       3030
#define ICON_SM_MEDKIT   1802
#define ICON_BOOSTER     1810
#define ICON_HEAT_CARD   1819
#define ICON_REPAIR_KIT  1813
#define ICON_MEDKIT      1803
#define ICON_CHEMBOMB    1808
#define ICON_FLASHBOMB   1805
#define ICON_NUKE        1809
#define ICON_CALTROPS    1829
#define ICON_FLAG        2520

#define STAR 2039
#define ELECTRO 2025

#define UZI_SMOKE 2146
#define UZI_SPARK 2140
#define SPIKES 2092
#define GRENADE 2019
#define BLANK 2200

#define BODY 1002
#define BODY_BURN 1003
#define BODY_SIZZLE 1011

#define DART_R0  2130
#define DART_R1  2131
#define DART_R2  2132
#define DART_R3  2133
#define DART_R4  2134
#define DART_R5  2135
#define DART_R6  2136
#define DART_R7  2137

#define BOLT_THINMAN_FRAMES 1
#define BOLT_THINMAN_R0 2018
#define BOLT_THINMAN_R1 BOLT_THINMAN_R0 - (BOLT_THINMAN_FRAMES * 1)
#define BOLT_THINMAN_R2 BOLT_THINMAN_R0 - (BOLT_THINMAN_FRAMES * 2)
#define BOLT_THINMAN_R3 BOLT_THINMAN_R0 - (BOLT_THINMAN_FRAMES * 3)
#define BOLT_THINMAN_R4 BOLT_THINMAN_R0 - (BOLT_THINMAN_FRAMES * 4)

#define SPEAR_FRAMES 1
#define SPEAR_R0 2030
#define SPEAR_R1 SPEAR_R0 + (SPEAR_FRAMES * 1)
#define SPEAR_R2 SPEAR_R0 + (SPEAR_FRAMES * 2)
#define SPEAR_R3 SPEAR_R0 + (SPEAR_FRAMES * 3)
#define SPEAR_R4 SPEAR_R0 + (SPEAR_FRAMES * 4)

#define STAR1      2049
#define EXP  3100 // Use new digitized explosion for big stuff
#define EXP2 2160 // My old explosion is still used for goro head
#define FIREBALL   2035
#define FIREBALL_FLAMES 3212

//////////////////////
//
// MISC
//
//////////////////////

#define COINCURSOR    2440  // Jim uses this for a text input cursor
#define STARTALPHANUM 4608  // New SW font for typing in stuff, It's in ASCII order.
#define ENDALPHANUM   4701

#define STATUS_BAR 2434
#define STATUS_KEYS 2881
#define STATUS_NUMBERS 2887
#define BORDER_TILE 2604

#define BLUE_KEY 1766
#define RED_KEY 1770
#define GREEN_KEY 1774
#define YELLOW_KEY 1778
#define GOLD_SKELKEY 1765
#define SILVER_SKELKEY 1769
#define BRONZE_SKELKEY 1773
#define RED_SKELKEY 1777
#define BLUE_CARD 1767
#define RED_CARD 1771
#define GREEN_CARD 1775
#define YELLOW_CARD 1779

#define BLUE_KEY_STATUE BLUE_KEY+2
#define RED_KEY_STATUE RED_KEY+2
#define GREEN_KEY_STATUE GREEN_KEY+2
#define YELLOW_KEY_STATUE YELLOW_KEY+2
#define SKEL_LOCKED 1846
#define SKEL_UNLOCKED 1847
#define RAMCARD_LOCKED 1850
#define RAMCARD_UNLOCKED 1851
#define CARD_LOCKED 1852
#define CARD_UNLOCKED 1853

#define WATER_BEGIN 320
#define WATER_END 320+8

#define WATER_BOIL 2305

#define FIRE_FLY0 630
#define FIRE_FLY1 631
#define FIRE_FLY2 632
#define FIRE_FLY3 633
#define FIRE_FLY4 634

#define FIRE_FLY_RATE 50

#define BREAK_LIGHT 443
#define BREAK_LIGHT_ANIM 447
#define BREAK_BARREL 453
#define BREAK_PEDISTAL 463
#define BREAK_BOTTLE1 468
#define BREAK_BOTTLE2 475
#define BREAK_MUSHROOM 666

//////////////////////
//
// COOLIE
//
//////////////////////

#define COOLIE_CHARGE_FRAMES 4
#define COOLIE_CHARGE_R0 1420
#define COOLIE_CHARGE_R1 COOLIE_CHARGE_R0 + (COOLIE_CHARGE_FRAMES * 1)
#define COOLIE_CHARGE_R2 COOLIE_CHARGE_R0 + (COOLIE_CHARGE_FRAMES * 2)
#define COOLIE_CHARGE_R3 COOLIE_CHARGE_R0 + (COOLIE_CHARGE_FRAMES * 3)
#define COOLIE_CHARGE_R4 COOLIE_CHARGE_R0 + (COOLIE_CHARGE_FRAMES * 4)

#define COOLIE_RUN_FRAMES 4
#define COOLIE_RUN_R0 1400
#define COOLIE_RUN_R1 COOLIE_RUN_R0 + (COOLIE_RUN_FRAMES * 1)
#define COOLIE_RUN_R2 COOLIE_RUN_R0 + (COOLIE_RUN_FRAMES * 2)
#define COOLIE_RUN_R3 COOLIE_RUN_R0 + (COOLIE_RUN_FRAMES * 3)
#define COOLIE_RUN_R4 COOLIE_RUN_R0 + (COOLIE_RUN_FRAMES * 4)

#define COOLIE_PAIN_FRAMES 1
#define COOLIE_PAIN_R0 1420
#define COOLIE_PAIN_R1 COOLIE_PAIN_R0 //+ (COOLIE_PAIN_FRAMES * 1)
#define COOLIE_PAIN_R2 COOLIE_PAIN_R0 //+ (COOLIE_PAIN_FRAMES * 2)
#define COOLIE_PAIN_R3 COOLIE_PAIN_R0 //+ (COOLIE_PAIN_FRAMES * 3)
#define COOLIE_PAIN_R4 COOLIE_PAIN_R0 //+ (COOLIE_PAIN_FRAMES * 4)

#define COOLG_RUN_FRAMES 4
#define COOLG_RUN_R0 4277
#define COOLG_RUN_R1 COOLG_RUN_R0 + (COOLG_RUN_FRAMES * 1)
#define COOLG_RUN_R2 COOLG_RUN_R0 + (COOLG_RUN_FRAMES * 2)
#define COOLG_RUN_R3 COOLG_RUN_R0 + (COOLG_RUN_FRAMES * 3)
#define COOLG_RUN_R4 COOLG_RUN_R0 + (COOLG_RUN_FRAMES * 4)

#define COOLG_CLUB_FRAMES 2
#define COOLG_CLUB_R0 1451
#define COOLG_CLUB_R1 COOLG_CLUB_R0 + (COOLG_CLUB_FRAMES * 1)
#define COOLG_CLUB_R2 COOLG_CLUB_R0 + (COOLG_CLUB_FRAMES * 2)
#define COOLG_CLUB_R3 COOLG_CLUB_R0 + (COOLG_CLUB_FRAMES * 3)
#define COOLG_CLUB_R4 COOLG_CLUB_R0 + (COOLG_CLUB_FRAMES * 4)

#define COOLG_FIRE_FRAMES 3
#define COOLG_FIRE_R0 4297
#define COOLG_FIRE_R1 COOLG_FIRE_R0 + (COOLG_FIRE_FRAMES * 1)
#define COOLG_FIRE_R2 COOLG_FIRE_R0 + (COOLG_FIRE_FRAMES * 2)
//#define COOLG_FIRE_R3 COOLG_FIRE_R0 + (COOLG_FIRE_FRAMES * 3)
//#define COOLG_FIRE_R4 COOLG_FIRE_R0 + (COOLG_FIRE_FRAMES * 4)

#define COOLG_PAIN_FRAMES 1
#define COOLG_PAIN_R0 4306
#define COOLG_PAIN_R1 COOLG_PAIN_R0 //+ (COOLIE_PAIN_FRAMES * 1)
#define COOLG_PAIN_R2 COOLG_PAIN_R0 //+ (COOLIE_PAIN_FRAMES * 2)
#define COOLG_PAIN_R3 COOLG_PAIN_R0 //+ (COOLIE_PAIN_FRAMES * 3)
#define COOLG_PAIN_R4 COOLG_PAIN_R0 //+ (COOLIE_PAIN_FRAMES * 4)

#define COOLIE_DEAD_NOHEAD 1440
#define COOLIE_DIE 4260
#define COOLIE_DEAD 4268

//////////////////////
//
//  PLAYER NINJA
//
//////////////////////

#define PLAYER_NINJA_SHOOT_FRAMES 1
#define PLAYER_NINJA_SHOOT_R0 1069
#define PLAYER_NINJA_SHOOT_R1 PLAYER_NINJA_SHOOT_R0 + (PLAYER_NINJA_SHOOT_FRAMES * 2)
#define PLAYER_NINJA_SHOOT_R2 PLAYER_NINJA_SHOOT_R0 + (PLAYER_NINJA_SHOOT_FRAMES * 3)
#define PLAYER_NINJA_SHOOT_R3 PLAYER_NINJA_SHOOT_R0 + (PLAYER_NINJA_SHOOT_FRAMES * 4)
#define PLAYER_NINJA_SHOOT_R4 PLAYER_NINJA_SHOOT_R0 + (PLAYER_NINJA_SHOOT_FRAMES * 1)

#define PLAYER_NINJA_RUN_FRAMES 4
#define PLAYER_NINJA_RUN_R0 1094
#define PLAYER_NINJA_RUN_R1 PLAYER_NINJA_RUN_R0 + (PLAYER_NINJA_RUN_FRAMES * 1)
#define PLAYER_NINJA_RUN_R2 PLAYER_NINJA_RUN_R0 + (PLAYER_NINJA_RUN_FRAMES * 2)
#define PLAYER_NINJA_RUN_R3 PLAYER_NINJA_RUN_R0 + (PLAYER_NINJA_RUN_FRAMES * 3)
#define PLAYER_NINJA_RUN_R4 PLAYER_NINJA_RUN_R0 + (PLAYER_NINJA_RUN_FRAMES * 4)

#define ZOMBIE_RUN_R0 PLAYER_NINJA_RUN_R0+1

#define PLAYER_NINJA_STAND_FRAMES 1
#define PLAYER_NINJA_STAND_R0 PLAYER_NINJA_RUN_R0
#define PLAYER_NINJA_STAND_R1 PLAYER_NINJA_RUN_R1
#define PLAYER_NINJA_STAND_R2 PLAYER_NINJA_RUN_R2
#define PLAYER_NINJA_STAND_R3 PLAYER_NINJA_RUN_R3
#define PLAYER_NINJA_STAND_R4 PLAYER_NINJA_RUN_R4

#define PLAYER_NINJA_JUMP_FRAMES 4
#define PLAYER_NINJA_JUMP_R0 1074
#define PLAYER_NINJA_JUMP_R1 PLAYER_NINJA_JUMP_R0 + (PLAYER_NINJA_JUMP_FRAMES * 1)
#define PLAYER_NINJA_JUMP_R2 PLAYER_NINJA_JUMP_R0 + (PLAYER_NINJA_JUMP_FRAMES * 2)
#define PLAYER_NINJA_JUMP_R3 PLAYER_NINJA_JUMP_R0 + (PLAYER_NINJA_JUMP_FRAMES * 3)
#define PLAYER_NINJA_JUMP_R4 PLAYER_NINJA_JUMP_R0 + (PLAYER_NINJA_JUMP_FRAMES * 4)

#define PLAYER_NINJA_FALL_R0 PLAYER_NINJA_JUMP_R0+2
#define PLAYER_NINJA_FALL_R1 PLAYER_NINJA_JUMP_R1+2
#define PLAYER_NINJA_FALL_R2 PLAYER_NINJA_JUMP_R2+2
#define PLAYER_NINJA_FALL_R3 PLAYER_NINJA_JUMP_R3+2
#define PLAYER_NINJA_FALL_R4 PLAYER_NINJA_JUMP_R4+2

#define PLAYER_NINJA_CLIMB_FRAMES 4
#define PLAYER_NINJA_CLIMB_R0 1024
#define PLAYER_NINJA_CLIMB_R1 PLAYER_NINJA_CLIMB_R0 + (PLAYER_NINJA_CLIMB_FRAMES * 1)
#define PLAYER_NINJA_CLIMB_R2 PLAYER_NINJA_CLIMB_R0 + (PLAYER_NINJA_CLIMB_FRAMES * 2)
#define PLAYER_NINJA_CLIMB_R3 PLAYER_NINJA_CLIMB_R0 + (PLAYER_NINJA_CLIMB_FRAMES * 3)
#define PLAYER_NINJA_CLIMB_R4 PLAYER_NINJA_CLIMB_R0 + (PLAYER_NINJA_CLIMB_FRAMES * 4)

#define PLAYER_NINJA_CRAWL_FRAMES 4
#define PLAYER_NINJA_CRAWL_R0 1044
#define PLAYER_NINJA_CRAWL_R1 PLAYER_NINJA_CRAWL_R0 + (PLAYER_NINJA_CRAWL_FRAMES * 1)
#define PLAYER_NINJA_CRAWL_R2 PLAYER_NINJA_CRAWL_R0 + (PLAYER_NINJA_CRAWL_FRAMES * 2)
#define PLAYER_NINJA_CRAWL_R3 PLAYER_NINJA_CRAWL_R0 + (PLAYER_NINJA_CRAWL_FRAMES * 3)
#define PLAYER_NINJA_CRAWL_R4 PLAYER_NINJA_CRAWL_R0 + (PLAYER_NINJA_CRAWL_FRAMES * 4)

#define PLAYER_NINJA_SWIM_FRAMES 4
#define PLAYER_NINJA_SWIM_R0 1114
#define PLAYER_NINJA_SWIM_R1 PLAYER_NINJA_SWIM_R0 + (PLAYER_NINJA_SWIM_FRAMES * 1)
#define PLAYER_NINJA_SWIM_R2 PLAYER_NINJA_SWIM_R0 + (PLAYER_NINJA_SWIM_FRAMES * 2)
#define PLAYER_NINJA_SWIM_R3 PLAYER_NINJA_SWIM_R0 + (PLAYER_NINJA_SWIM_FRAMES * 3)
#define PLAYER_NINJA_SWIM_R4 PLAYER_NINJA_SWIM_R0 + (PLAYER_NINJA_SWIM_FRAMES * 4)

#define PLAYER_NINJA_SWORD_FRAMES 3
#define PLAYER_NINJA_SWORD_R0 1161
#define PLAYER_NINJA_SWORD_R1 PLAYER_NINJA_SWORD_R0 + (PLAYER_NINJA_SWORD_FRAMES * 1)
#define PLAYER_NINJA_SWORD_R2 PLAYER_NINJA_SWORD_R0 + (PLAYER_NINJA_SWORD_FRAMES * 2)
#define PLAYER_NINJA_SWORD_R3 PLAYER_NINJA_SWORD_R0 + (PLAYER_NINJA_SWORD_FRAMES * 3)
#define PLAYER_NINJA_SWORD_R4 PLAYER_NINJA_SWORD_R0 + (PLAYER_NINJA_SWORD_FRAMES * 4)

#define PLAYER_NINJA_PUNCH_FRAMES 2
#define PLAYER_NINJA_PUNCH_R0 1176
#define PLAYER_NINJA_PUNCH_R1 PLAYER_NINJA_PUNCH_R0 + (PLAYER_NINJA_PUNCH_FRAMES * 1)
#define PLAYER_NINJA_PUNCH_R2 PLAYER_NINJA_PUNCH_R0 + (PLAYER_NINJA_PUNCH_FRAMES * 2)
#define PLAYER_NINJA_PUNCH_R3 PLAYER_NINJA_PUNCH_R0 + (PLAYER_NINJA_PUNCH_FRAMES * 3)
#define PLAYER_NINJA_PUNCH_R4 PLAYER_NINJA_PUNCH_R0 + (PLAYER_NINJA_PUNCH_FRAMES * 4)

#define PLAYER_NINJA_KICK_FRAMES 2
#define PLAYER_NINJA_KICK_R0 1186
#define PLAYER_NINJA_KICK_R1 PLAYER_NINJA_KICK_R0 + (PLAYER_NINJA_KICK_FRAMES * 1)
#define PLAYER_NINJA_KICK_R2 PLAYER_NINJA_KICK_R0 + (PLAYER_NINJA_KICK_FRAMES * 2)
#define PLAYER_NINJA_KICK_R3 PLAYER_NINJA_KICK_R0 + (PLAYER_NINJA_KICK_FRAMES * 3)
#define PLAYER_NINJA_KICK_R4 PLAYER_NINJA_KICK_R0 + (PLAYER_NINJA_KICK_FRAMES * 4)

#define PLAYER_NINJA_DIE    1152
#define PLAYER_NINJA_FLY    1069

//////////////////////
//
//  EVIL NINJA
//
//////////////////////

#define NINJA_RUN_FRAMES 4
#define NINJA_RUN_R0 4096
#define NINJA_RUN_R1 NINJA_RUN_R0 + (NINJA_RUN_FRAMES * 1)
#define NINJA_RUN_R2 NINJA_RUN_R0 + (NINJA_RUN_FRAMES * 2)
#define NINJA_RUN_R3 NINJA_RUN_R0 + (NINJA_RUN_FRAMES * 3)
#define NINJA_RUN_R4 NINJA_RUN_R0 + (NINJA_RUN_FRAMES * 4)

#define NINJA_STAND_FRAMES 1
#define NINJA_STAND_R0 NINJA_RUN_R0
#define NINJA_STAND_R1 NINJA_RUN_R1
#define NINJA_STAND_R2 NINJA_RUN_R2
#define NINJA_STAND_R3 NINJA_RUN_R3
#define NINJA_STAND_R4 NINJA_RUN_R4

#define NINJA_CRAWL_FRAMES 4
#define NINJA_CRAWL_R0 4162
#define NINJA_CRAWL_R1 NINJA_CRAWL_R0 + (NINJA_CRAWL_FRAMES * 1)
#define NINJA_CRAWL_R2 NINJA_CRAWL_R0 + (NINJA_CRAWL_FRAMES * 2)
#define NINJA_CRAWL_R3 NINJA_CRAWL_R0 + (NINJA_CRAWL_FRAMES * 3)
#define NINJA_CRAWL_R4 NINJA_CRAWL_R0 + (NINJA_CRAWL_FRAMES * 4)

#define NINJA_SWIM_FRAMES 4
#define NINJA_SWIM_R0 4122
#define NINJA_SWIM_R1 NINJA_SWIM_R0 + (NINJA_SWIM_FRAMES * 1)
#define NINJA_SWIM_R2 NINJA_SWIM_R0 + (NINJA_SWIM_FRAMES * 2)
#define NINJA_SWIM_R3 NINJA_SWIM_R0 + (NINJA_SWIM_FRAMES * 3)
#define NINJA_SWIM_R4 NINJA_SWIM_R0 + (NINJA_SWIM_FRAMES * 4)

#define NINJA_HARI_KARI_FRAMES 8
#define NINJA_HARI_KARI_R0 4211
#define NINJA_HARI_KARI_R1 NINJA_HARI_KARI_R0
#define NINJA_HARI_KARI_R2 NINJA_HARI_KARI_R0
#define NINJA_HARI_KARI_R3 NINJA_HARI_KARI_R0
#define NINJA_HARI_KARI_R4 NINJA_HARI_KARI_R0

#define NINJA_CLIMB_FRAMES 4
#define NINJA_CLIMB_R0 4182
#define NINJA_CLIMB_R1 NINJA_CLIMB_R0 + (NINJA_CLIMB_FRAMES * 1)
#define NINJA_CLIMB_R2 NINJA_CLIMB_R0 + (NINJA_CLIMB_FRAMES * 2)
#define NINJA_CLIMB_R3 NINJA_CLIMB_R0 + (NINJA_CLIMB_FRAMES * 3)
#define NINJA_CLIMB_R4 NINJA_CLIMB_R0 + (NINJA_CLIMB_FRAMES * 4)

#define NINJA_THROW_FRAMES 3
#define NINJA_THROW_R0 4202
#define NINJA_THROW_R1 NINJA_THROW_R0 + (NINJA_THROW_FRAMES * 1)
#define NINJA_THROW_R2 NINJA_THROW_R0 + (NINJA_THROW_FRAMES * 2)

// don't have rotations for pain frames currently

#if 1
#define NINJA_PAIN_FRAMES 2
#define NINJA_PAIN_R0 4219   //4164
#define NINJA_PAIN_R1 NINJA_PAIN_R0
#define NINJA_PAIN_R2 NINJA_PAIN_R0
#define NINJA_PAIN_R3 NINJA_PAIN_R0
#define NINJA_PAIN_R4 NINJA_PAIN_R0
#endif

#define NINJA_JUMP_FRAMES 4
#define NINJA_JUMP_R0 4142
#define NINJA_JUMP_R1 NINJA_JUMP_R0 + (NINJA_JUMP_FRAMES * 1)
#define NINJA_JUMP_R2 NINJA_JUMP_R0 + (NINJA_JUMP_FRAMES * 2)
#define NINJA_JUMP_R3 NINJA_JUMP_R0 + (NINJA_JUMP_FRAMES * 3)
#define NINJA_JUMP_R4 NINJA_JUMP_R0 + (NINJA_JUMP_FRAMES * 4)

#define NINJA_FALL_R0 NINJA_JUMP_R0+2
#define NINJA_FALL_R1 NINJA_JUMP_R1+2
#define NINJA_FALL_R2 NINJA_JUMP_R2+2
#define NINJA_FALL_R3 NINJA_JUMP_R3+2
#define NINJA_FALL_R4 NINJA_JUMP_R4+2

#define NINJA_LAND_R0 NINJA_JUMP_R0+3
#define NINJA_LAND_R1 NINJA_JUMP_R1+3
#define NINJA_LAND_R2 NINJA_JUMP_R2+3
#define NINJA_LAND_R3 NINJA_JUMP_R3+3
#define NINJA_LAND_R4 NINJA_JUMP_R4+3

#define NINJA_KNEEL_R0 NINJA_CRAWL_R0
#define NINJA_KNEEL_R1 NINJA_CRAWL_R1
#define NINJA_KNEEL_R2 NINJA_CRAWL_R2
#define NINJA_KNEEL_R3 NINJA_CRAWL_R3
#define NINJA_KNEEL_R4 NINJA_CRAWL_R4

#define NINJA_FLY_FRAMES 2
#define NINJA_FLY_R0 4116
#define NINJA_FLY_R1 NINJA_FLY_R0 + (NINJA_FLY_FRAMES * 1)
#define NINJA_FLY_R2 NINJA_FLY_R0 + (NINJA_FLY_FRAMES * 2)
#define NINJA_FLY_R3 NINJA_FLY_R0 + (NINJA_FLY_FRAMES * 3)
#define NINJA_FLY_R4 NINJA_FLY_R0 + (NINJA_FLY_FRAMES * 4)

#define NINJA_FIRE_FRAMES 2
#define NINJA_FIRE_R0 4116
#define NINJA_FIRE_R1 NINJA_FIRE_R0 + (NINJA_FIRE_FRAMES * 1)
#define NINJA_FIRE_R2 NINJA_FIRE_R0 + (NINJA_FIRE_FRAMES * 2)
#define NINJA_FIRE_R3 NINJA_FIRE_R0 + (NINJA_FIRE_FRAMES * 3)
#define NINJA_FIRE_R4 NINJA_FIRE_R0 + (NINJA_FIRE_FRAMES * 4)

#define NINJA_DIE 4219
#define NINJA_DEAD NINJA_DIE+8

#define NINJA_SLICED 4227
#define NINJA_DEAD_SLICED NINJA_SLICED+9

#define NINJA_Head_FRAMES 1
#define NINJA_Head_R0 1142
#define NINJA_Head_R1 NINJA_Head_R0 + (NINJA_Head_FRAMES * 1)
#define NINJA_Head_R2 NINJA_Head_R0 + (NINJA_Head_FRAMES * 2)
#define NINJA_Head_R3 NINJA_Head_R0 + (NINJA_Head_FRAMES * 3)
#define NINJA_Head_R4 NINJA_Head_R0 + (NINJA_Head_FRAMES * 4)

#define NINJA_HeadHurl_FRAMES 1
#define NINJA_HeadHurl_R0 1147
#define NINJA_HeadHurl_R1 NINJA_HeadHurl_R0 + (NINJA_HeadHurl_FRAMES * 1)
#define NINJA_HeadHurl_R2 NINJA_HeadHurl_R0 + (NINJA_HeadHurl_FRAMES * 2)
#define NINJA_HeadHurl_R3 NINJA_HeadHurl_R0 + (NINJA_HeadHurl_FRAMES * 3)
#define NINJA_HeadHurl_R4 NINJA_HeadHurl_R0 + (NINJA_HeadHurl_FRAMES * 4)

//////////////////////
//
// SERP BOSS
//
//////////////////////

#define SERP_RUN_FRAMES 3
#define SERP_RUN_R0 1300
#define SERP_RUN_R1 SERP_RUN_R0 + (SERP_RUN_FRAMES * 1)
#define SERP_RUN_R2 SERP_RUN_R0 + (SERP_RUN_FRAMES * 2)
#define SERP_RUN_R3 SERP_RUN_R0 + (SERP_RUN_FRAMES * 3)
#define SERP_RUN_R4 SERP_RUN_R0 + (SERP_RUN_FRAMES * 4)

#define SERP_SLASH_FRAMES 5
#define SERP_SLASH_R0 972
#define SERP_SLASH_R1 SERP_SLASH_R0 + (SERP_SLASH_FRAMES * 1)
#define SERP_SLASH_R2 SERP_SLASH_R0 + (SERP_SLASH_FRAMES * 2)
#define SERP_SLASH_R3 SERP_SLASH_R0 + (SERP_SLASH_FRAMES * 3)
#define SERP_SLASH_R4 SERP_SLASH_R0 + (SERP_SLASH_FRAMES * 4)

#define SERP_SPELL_FRAMES 4
#define SERP_SPELL_R0 997
#define SERP_SPELL_R1 SERP_SPELL_R0 + (SERP_SPELL_FRAMES * 1)
#define SERP_SPELL_R2 SERP_SPELL_R0 + (SERP_SPELL_FRAMES * 2)
#define SERP_SPELL_R3 SERP_SPELL_R0 + (SERP_SPELL_FRAMES * 3)
#define SERP_SPELL_R4 SERP_SPELL_R0 + (SERP_SPELL_FRAMES * 4)

#define SERP_DIE 960
#define SERP_DEAD 969

//////////////////////
//
// LAVA BOSS
//
//////////////////////

#define LAVA_RUN_FRAMES 1
#define LAVA_RUN_R0 2355
#define LAVA_RUN_R1 LAVA_RUN_R0 //+ (LAVA_RUN_FRAMES * 1)
#define LAVA_RUN_R2 LAVA_RUN_R0 //+ (LAVA_RUN_FRAMES * 2)
#define LAVA_RUN_R3 LAVA_RUN_R0 //+ (LAVA_RUN_FRAMES * 3)
#define LAVA_RUN_R4 LAVA_RUN_R0 //+ (LAVA_RUN_FRAMES * 4)

#define LAVA_THROW_FRAMES 1
#define LAVA_THROW_R0 2355
#define LAVA_THROW_R1 LAVA_THROW_R0 //+ (LAVA_THROW_FRAMES * 1)
#define LAVA_THROW_R2 LAVA_THROW_R0 //+ (LAVA_THROW_FRAMES * 2)
#define LAVA_THROW_R3 LAVA_THROW_R0 //+ (LAVA_THROW_FRAMES * 3)
#define LAVA_THROW_R4 LAVA_THROW_R0 //+ (LAVA_THROW_FRAMES * 4)

#define LAVA_FLAME_FRAMES 1
#define LAVA_FLAME_R0 2355
#define LAVA_FLAME_R1 LAVA_FLAME_R0 //+ (LAVA_FLAME_FRAMES * 1)
#define LAVA_FLAME_R2 LAVA_FLAME_R0 //+ (LAVA_FLAME_FRAMES * 2)
#define LAVA_FLAME_R3 LAVA_FLAME_R0 //+ (LAVA_FLAME_FRAMES * 3)
#define LAVA_FLAME_R4 LAVA_FLAME_R0 //+ (LAVA_FLAME_FRAMES * 4)

#define LAVA_DIE 2355
#define LAVA_DEAD 2355

// 10 frames
#define LAVA_BOULDER 2196

//////////////////////
//
// SKEL
//
//////////////////////

#define SKEL_RUN_FRAMES 6
#define SKEL_RUN_R0 1367
#define SKEL_RUN_R1 SKEL_RUN_R0 + (SKEL_RUN_FRAMES * 1)
#define SKEL_RUN_R2 SKEL_RUN_R0 + (SKEL_RUN_FRAMES * 2)
#define SKEL_RUN_R3 SKEL_RUN_R0 + (SKEL_RUN_FRAMES * 3)
#define SKEL_RUN_R4 SKEL_RUN_R0 + (SKEL_RUN_FRAMES * 4)

#define SKEL_SLASH_FRAMES 3
#define SKEL_SLASH_R0 1326
#define SKEL_SLASH_R1 SKEL_SLASH_R0 + (SKEL_SLASH_FRAMES * 1)
#define SKEL_SLASH_R2 SKEL_SLASH_R0 + (SKEL_SLASH_FRAMES * 2)
#define SKEL_SLASH_R3 SKEL_SLASH_R0 + (SKEL_SLASH_FRAMES * 3)
#define SKEL_SLASH_R4 SKEL_SLASH_R0 + (SKEL_SLASH_FRAMES * 4)

#define SKEL_SPELL_FRAMES 4
#define SKEL_SPELL_R0 1341
#define SKEL_SPELL_R1 SKEL_SPELL_R0 + (SKEL_SPELL_FRAMES * 1)
#define SKEL_SPELL_R2 SKEL_SPELL_R0 + (SKEL_SPELL_FRAMES * 2)
#define SKEL_SPELL_R3 SKEL_SPELL_R0 + (SKEL_SPELL_FRAMES * 3)
#define SKEL_SPELL_R4 SKEL_SPELL_R0 + (SKEL_SPELL_FRAMES * 4)

#define SKEL_PAIN_FRAMES 1
#define SKEL_PAIN_R0 SKEL_SLASH_R0+1
#define SKEL_PAIN_R1 SKEL_SLASH_R1+1
#define SKEL_PAIN_R2 SKEL_SLASH_R2+1
#define SKEL_PAIN_R3 SKEL_SLASH_R3+1
#define SKEL_PAIN_R4 SKEL_SLASH_R4+1

#define SKEL_TELEPORT 1361
#define SKEL_DIE 1320

//////////////////////
//
// GORO
//
//////////////////////

#define GORO_RUN_FRAMES 4
#define GORO_RUN_R0 1469
#define GORO_RUN_R1 GORO_RUN_R0 + (GORO_RUN_FRAMES * 1)
#define GORO_RUN_R2 GORO_RUN_R0 + (GORO_RUN_FRAMES * 2)
#define GORO_RUN_R3 GORO_RUN_R0 + (GORO_RUN_FRAMES * 3)
#define GORO_RUN_R4 GORO_RUN_R0 + (GORO_RUN_FRAMES * 4)

#define GORO_CHOP_FRAMES 3
#define GORO_CHOP_R0 1489
#define GORO_CHOP_R1 GORO_CHOP_R0 + (GORO_CHOP_FRAMES * 1)
#define GORO_CHOP_R2 GORO_CHOP_R0 + (GORO_CHOP_FRAMES * 2)
#define GORO_CHOP_R3 GORO_RUN_R3
#define GORO_CHOP_R4 GORO_RUN_R4

#define GORO_STAND_R0 GORO_CHOP_R0
#define GORO_STAND_R1 GORO_CHOP_R1
#define GORO_STAND_R2 GORO_CHOP_R2
#define GORO_STAND_R3 GORO_CHOP_R3
#define GORO_STAND_R4 GORO_CHOP_R4

#define GORO_SPELL_FRAMES 2
#define GORO_SPELL_R0 1513
#define GORO_SPELL_R1 GORO_SPELL_R0 + (GORO_SPELL_FRAMES * 1)
#define GORO_SPELL_R2 GORO_SPELL_R0 + (GORO_SPELL_FRAMES * 2)
#define GORO_SPELL_R3 GORO_RUN_R3
#define GORO_SPELL_R4 GORO_RUN_R4

#define GORO_DIE 1504
#define GORO_DEAD 1504+8

//////////////////////
//
// FIREBALL
//
//////////////////////

#define FIREBALL_FRAMES 4
#define FIREBALL_R0 3192
#define FIREBALL_R1 FIREBALL_R0 + (FIREBALL_FRAMES * 1)
#define FIREBALL_R2 FIREBALL_R0 + (FIREBALL_FRAMES * 2)
#define FIREBALL_R3 FIREBALL_R0 + (FIREBALL_FRAMES * 3)
#define FIREBALL_R4 FIREBALL_R0 + (FIREBALL_FRAMES * 4)

//////////////////////
//
// HORNET
//
//////////////////////

#define HORNET_RUN_FRAMES 2
#define HORNET_RUN_R0 800
#define HORNET_RUN_R1 HORNET_RUN_R0 + (HORNET_RUN_FRAMES * 1)
#define HORNET_RUN_R2 HORNET_RUN_R0 + (HORNET_RUN_FRAMES * 2)
#define HORNET_RUN_R3 HORNET_RUN_R0 + (HORNET_RUN_FRAMES * 3)
#define HORNET_RUN_R4 HORNET_RUN_R0 + (HORNET_RUN_FRAMES * 4)

#define HORNET_DIE 810
#define HORNET_DEAD 811

//////////////////////
//
// SKULL
//
//////////////////////

#define SKULL_FRAMES 1
#define SKULL_R0 820
#define SKULL_R1 SKULL_R0 + (SKULL_FRAMES * 1)
#define SKULL_R2 SKULL_R0 + (SKULL_FRAMES * 2)
#define SKULL_R3 SKULL_R0 + (SKULL_FRAMES * 3)
#define SKULL_R4 SKULL_R0 + (SKULL_FRAMES * 4)

#define SKULL_DIE 825
#define SKULL_EXPLODE 825

#define SKULL_SERP (SKULL_R0 + 2)

// MECHANICAL BETTY VERSION
#define BETTY_FRAMES 3
#define BETTY_R0 817
#define BETTY_R1 BETTY_R0
#define BETTY_R2 BETTY_R0
#define BETTY_R3 BETTY_R0
#define BETTY_R4 BETTY_R0

//////////////////////
//
// RIPPER
//
//////////////////////
#define RIPPER_RUN_FRAMES 4
#define RIPPER_RUN_R0 1580
#define RIPPER_RUN_R1 RIPPER_RUN_R0 + (RIPPER_RUN_FRAMES * 1)
#define RIPPER_RUN_R2 RIPPER_RUN_R0 + (RIPPER_RUN_FRAMES * 2)
#define RIPPER_RUN_R3 RIPPER_RUN_R0 + (RIPPER_RUN_FRAMES * 3)
#define RIPPER_RUN_R4 RIPPER_RUN_R0 + (RIPPER_RUN_FRAMES * 4)

#define RIPPER_JUMP_FRAMES 2
#define RIPPER_JUMP_R0 1620
#define RIPPER_JUMP_R1 RIPPER_JUMP_R0 + (RIPPER_JUMP_FRAMES * 1)
#define RIPPER_JUMP_R2 RIPPER_JUMP_R0 + (RIPPER_JUMP_FRAMES * 2)
#define RIPPER_JUMP_R3 RIPPER_JUMP_R0 + (RIPPER_JUMP_FRAMES * 3)
#define RIPPER_JUMP_R4 RIPPER_JUMP_R0 + (RIPPER_JUMP_FRAMES * 4)

#define RIPPER_FALL_R0 RIPPER_JUMP_R0+1
#define RIPPER_FALL_R1 RIPPER_JUMP_R1+1
#define RIPPER_FALL_R2 RIPPER_JUMP_R2+1
#define RIPPER_FALL_R3 RIPPER_JUMP_R3+1
#define RIPPER_FALL_R4 RIPPER_JUMP_R4+1

#define RIPPER_STAND_R0 RIPPER_JUMP_R0
#define RIPPER_STAND_R1 RIPPER_JUMP_R1
#define RIPPER_STAND_R2 RIPPER_JUMP_R2
#define RIPPER_STAND_R3 RIPPER_JUMP_R3
#define RIPPER_STAND_R4 RIPPER_JUMP_R4

#define RIPPER_HANG_FRAMES 1
#define RIPPER_HANG_R0 1645
#define RIPPER_HANG_R1 1645
#define RIPPER_HANG_R2 1639
#define RIPPER_HANG_R3 1637
#define RIPPER_HANG_R4 1635

#define RIPPER_SWIPE_FRAMES 4
#define RIPPER_SWIPE_R0 1600
#define RIPPER_SWIPE_R1 RIPPER_SWIPE_R0 + (RIPPER_SWIPE_FRAMES * 1)
#define RIPPER_SWIPE_R2 RIPPER_SWIPE_R0 + (RIPPER_SWIPE_FRAMES * 2)
#define RIPPER_SWIPE_R3 RIPPER_SWIPE_R0 + (RIPPER_SWIPE_FRAMES * 3)
#define RIPPER_SWIPE_R4 RIPPER_SWIPE_R0 + (RIPPER_SWIPE_FRAMES * 4)

#define RIPPER_HEART_FRAMES 1
#define RIPPER_HEART_R0 1635
#define RIPPER_HEART_R1 RIPPER_HEART_R0
#define RIPPER_HEART_R2 RIPPER_HEART_R0
#define RIPPER_HEART_R3 RIPPER_HEART_R0
#define RIPPER_HEART_R4 RIPPER_HEART_R0

#define RIPPER_DIE 1640
#define RIPPER_DEAD 1643

// The new Ripper
#define RIPPER2_RUN_FRAMES 4
#define RIPPER2_RUN_R0 4320
#define RIPPER2_RUN_R1 RIPPER2_RUN_R0 + (RIPPER2_RUN_FRAMES * 1)
#define RIPPER2_RUN_R2 RIPPER2_RUN_R0 + (RIPPER2_RUN_FRAMES * 2)
#define RIPPER2_RUN_R3 RIPPER2_RUN_R0 + (RIPPER2_RUN_FRAMES * 3)
#define RIPPER2_RUN_R4 RIPPER2_RUN_R0 + (RIPPER2_RUN_FRAMES * 4)

#define RIPPER2_RUNFAST_FRAMES 4
#define RIPPER2_RUNFAST_R0 4340
#define RIPPER2_RUNFAST_R1 RIPPER2_RUNFAST_R0 + (RIPPER2_RUNFAST_FRAMES * 1)
#define RIPPER2_RUNFAST_R2 RIPPER2_RUNFAST_R0 + (RIPPER2_RUNFAST_FRAMES * 2)
#define RIPPER2_RUNFAST_R3 RIPPER2_RUNFAST_R0 + (RIPPER2_RUNFAST_FRAMES * 3)
#define RIPPER2_RUNFAST_R4 RIPPER2_RUNFAST_R0 + (RIPPER2_RUNFAST_FRAMES * 4)

#define RIPPER2_JUMP_FRAMES 4
#define RIPPER2_JUMP_R0 4374
#define RIPPER2_JUMP_R1 RIPPER2_JUMP_R0 + (RIPPER2_JUMP_FRAMES * 1)
#define RIPPER2_JUMP_R2 RIPPER2_JUMP_R0 + (RIPPER2_JUMP_FRAMES * 2)
#define RIPPER2_JUMP_R3 RIPPER2_JUMP_R0 + (RIPPER2_JUMP_FRAMES * 3)
#define RIPPER2_JUMP_R4 RIPPER2_JUMP_R0 + (RIPPER2_JUMP_FRAMES * 4)

#define RIPPER2_FALL_R0 RIPPER2_JUMP_R0+2
#define RIPPER2_FALL_R1 RIPPER2_JUMP_R1+2
#define RIPPER2_FALL_R2 RIPPER2_JUMP_R2+2
#define RIPPER2_FALL_R3 RIPPER2_JUMP_R3+2
#define RIPPER2_FALL_R4 RIPPER2_JUMP_R4+2

#define RIPPER2_STAND_R0 RIPPER2_JUMP_R0+3
#define RIPPER2_STAND_R1 RIPPER2_JUMP_R1+3
#define RIPPER2_STAND_R2 RIPPER2_JUMP_R2+3
#define RIPPER2_STAND_R3 RIPPER2_JUMP_R3+3
#define RIPPER2_STAND_R4 RIPPER2_JUMP_R4+3

#define RIPPER2_HANG_FRAMES 1
#define RIPPER2_HANG_R0 4369
#define RIPPER2_HANG_R1 RIPPER2_HANG_R0 + (RIPPER2_HANG_FRAMES * 1)
#define RIPPER2_HANG_R2 RIPPER2_HANG_R0 + (RIPPER2_HANG_FRAMES * 2)
#define RIPPER2_HANG_R3 RIPPER2_HANG_R0 + (RIPPER2_HANG_FRAMES * 3)
#define RIPPER2_HANG_R4 RIPPER2_HANG_R0 + (RIPPER2_HANG_FRAMES * 4)

#define RIPPER2_SWIPE_FRAMES 4
#define RIPPER2_SWIPE_R0 4394
#define RIPPER2_SWIPE_R1 RIPPER2_SWIPE_R0 + (RIPPER2_SWIPE_FRAMES * 1)
#define RIPPER2_SWIPE_R2 RIPPER2_SWIPE_R0 + (RIPPER2_SWIPE_FRAMES * 2)
#define RIPPER2_SWIPE_R3 RIPPER2_SWIPE_R0 + (RIPPER2_SWIPE_FRAMES * 3)
#define RIPPER2_SWIPE_R4 RIPPER2_SWIPE_R0 + (RIPPER2_SWIPE_FRAMES * 4)

#define RIPPER2_MEKONG_FRAMES 3
#define RIPPER2_MEKONG_R0 4360
#define RIPPER2_MEKONG_R1 RIPPER2_MEKONG_R0 + (RIPPER2_MEKONG_FRAMES * 1)
#define RIPPER2_MEKONG_R2 RIPPER2_MEKONG_R0 + (RIPPER2_MEKONG_FRAMES * 2)
#define RIPPER2_MEKONG_R3 RIPPER2_MEKONG_R0 + (RIPPER2_MEKONG_FRAMES * 3)
#define RIPPER2_MEKONG_R4 RIPPER2_MEKONG_R0 + (RIPPER2_MEKONG_FRAMES * 4)

#define RIPPER2_HEART_FRAMES 2
#define RIPPER2_HEART_R0 4422
#define RIPPER2_HEART_R1 RIPPER2_HEART_R0
#define RIPPER2_HEART_R2 RIPPER2_HEART_R0
#define RIPPER2_HEART_R3 RIPPER2_HEART_R0
#define RIPPER2_HEART_R4 RIPPER2_HEART_R0

#define RIPPER2_DIE 4414    // Has 8 frames now
#define RIPPER2_DEAD 4421

//////////////////////
//
// EEL
//
//////////////////////

#define EEL_RUN_FRAMES 3
#define EEL_RUN_R0 3780
#define EEL_RUN_R1 EEL_RUN_R0 + (EEL_RUN_FRAMES * 1)
#define EEL_RUN_R2 EEL_RUN_R0 + (EEL_RUN_FRAMES * 2)
#define EEL_RUN_R3 EEL_RUN_R0 + (EEL_RUN_FRAMES * 3)
#define EEL_RUN_R4 EEL_RUN_R0 + (EEL_RUN_FRAMES * 4)

#define EEL_FIRE_FRAMES 3
#define EEL_FIRE_R0 3760
#define EEL_FIRE_R1 EEL_FIRE_R0 + (EEL_FIRE_FRAMES * 1)
#define EEL_FIRE_R2 EEL_FIRE_R0 + (EEL_FIRE_FRAMES * 2)
#define EEL_FIRE_R3 EEL_FIRE_R0 + (EEL_FIRE_FRAMES * 3)
#define EEL_FIRE_R4 EEL_RUN_R0  + (EEL_RUN_FRAMES  * 4)

#define EEL_DIE 3795
#define EEL_DEAD 3795

//////////////////////
//
// SUMO
//
//////////////////////

#define SUMO_RUN_FRAMES 4
#define SUMO_RUN_R0 1210
#define SUMO_RUN_R1 SUMO_RUN_R0 + (SUMO_RUN_FRAMES * 1)
#define SUMO_RUN_R2 SUMO_RUN_R0 + (SUMO_RUN_FRAMES * 2)
#define SUMO_RUN_R3 SUMO_RUN_R0 + (SUMO_RUN_FRAMES * 3)
#define SUMO_RUN_R4 SUMO_RUN_R0 + (SUMO_RUN_FRAMES * 4)

#define SUMO_PAIN_FRAMES 1
#define SUMO_PAIN_R0 1265
#define SUMO_PAIN_R1 SUMO_PAIN_R0 //+ (SUMO_PAIN_FRAMES * 1)
#define SUMO_PAIN_R2 SUMO_PAIN_R0 //+ (SUMO_PAIN_FRAMES * 2)
#define SUMO_PAIN_R3 SUMO_PAIN_R0 //+ (SUMO_PAIN_FRAMES * 3)
#define SUMO_PAIN_R4 SUMO_PAIN_R0 //+ (SUMO_PAIN_FRAMES * 4)

#define SUMO_STOMP_FRAMES 3
#define SUMO_STOMP_R0 1230
#define SUMO_STOMP_R1 SUMO_STOMP_R0 + (SUMO_STOMP_FRAMES * 1)
#define SUMO_STOMP_R2 SUMO_STOMP_R0 + (SUMO_STOMP_FRAMES * 2)
#define SUMO_STOMP_R3 SUMO_STOMP_R0 + (SUMO_STOMP_FRAMES * 3)
#define SUMO_STOMP_R4 SUMO_STOMP_R0 + (SUMO_STOMP_FRAMES * 4)

#define SUMO_CLAP_FRAMES 4
#define SUMO_CLAP_R0 1245
#define SUMO_CLAP_R1 SUMO_CLAP_R0 + (SUMO_CLAP_FRAMES * 1)
#define SUMO_CLAP_R2 SUMO_CLAP_R0 + (SUMO_CLAP_FRAMES * 2)
#define SUMO_CLAP_R3 SUMO_CLAP_R0 + (SUMO_CLAP_FRAMES * 3)
#define SUMO_CLAP_R4 SUMO_CLAP_R0 + (SUMO_CLAP_FRAMES * 4)

#define SUMO_FART_FRAMES 4
#define SUMO_FART_R0 1280
#define SUMO_FART_R1 SUMO_FART_R0
#define SUMO_FART_R2 SUMO_FART_R0
#define SUMO_FART_R3 SUMO_FART_R0
#define SUMO_FART_R4 SUMO_FART_R0

#define SUMO_DIE 1270
#define SUMO_DEAD 1277

#define TRASHCAN 2540

//////////////////////
//
// GIRLS
//
//////////////////////
#define TOILETGIRL_R0 5023
#define WASHGIRL_R0 5032
#define MECHANICGIRL_R0 4590
#define CARGIRL_R0 4594
#define SAILORGIRL_R0 4600
#define PRUNEGIRL_R0 4604

// Pachinko machines
#define PACHINKO1 4768
#define PACHINKO2 4792
#define PACHINKO3 4816
#define PACHINKO4 4840

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

//////////////////////
//
// BUNNY
//
//////////////////////
#define BUNNY_RUN_FRAMES 5
#define BUNNY_RUN_R0 4550
#define BUNNY_RUN_R1 BUNNY_RUN_R0 + (BUNNY_RUN_FRAMES * 1)
#define BUNNY_RUN_R2 BUNNY_RUN_R0 + (BUNNY_RUN_FRAMES * 2)
#define BUNNY_RUN_R3 BUNNY_RUN_R0 + (BUNNY_RUN_FRAMES * 3)
#define BUNNY_RUN_R4 BUNNY_RUN_R0 + (BUNNY_RUN_FRAMES * 4)

#define BUNNY_STAND_R0 BUNNY_RUN_R0
#define BUNNY_STAND_R1 BUNNY_RUN_R1
#define BUNNY_STAND_R2 BUNNY_RUN_R2
#define BUNNY_STAND_R3 BUNNY_RUN_R3
#define BUNNY_STAND_R4 BUNNY_RUN_R4

#define BUNNY_SWIPE_FRAMES 5
#define BUNNY_SWIPE_R0 4575
#define BUNNY_SWIPE_R1 BUNNY_SWIPE_R0 + (BUNNY_SWIPE_FRAMES * 1)
#define BUNNY_SWIPE_R2 BUNNY_SWIPE_R0 + (BUNNY_SWIPE_FRAMES * 1)
#define BUNNY_SWIPE_R3 BUNNY_SWIPE_R0 + (BUNNY_SWIPE_FRAMES * 1)
#define BUNNY_SWIPE_R4 BUNNY_SWIPE_R0 + (BUNNY_SWIPE_FRAMES * 1)

#define BUNNY_DIE 4580
#define BUNNY_DEAD 4584

//////////////////////
//
//  EVIL GIRLNINJA
//
//////////////////////

#define GIRLNINJA_RUN_FRAMES 4
#define GIRLNINJA_RUN_R0 5162
#define GIRLNINJA_RUN_R1 GIRLNINJA_RUN_R0 + (GIRLNINJA_RUN_FRAMES * 1)
#define GIRLNINJA_RUN_R2 GIRLNINJA_RUN_R0 + (GIRLNINJA_RUN_FRAMES * 2)
#define GIRLNINJA_RUN_R3 GIRLNINJA_RUN_R0 + (GIRLNINJA_RUN_FRAMES * 3)
#define GIRLNINJA_RUN_R4 GIRLNINJA_RUN_R0 + (GIRLNINJA_RUN_FRAMES * 4)

#define GIRLNINJA_STAND_FRAMES 1
#define GIRLNINJA_STAND_R0 GIRLNINJA_RUN_R0
#define GIRLNINJA_STAND_R1 GIRLNINJA_RUN_R1
#define GIRLNINJA_STAND_R2 GIRLNINJA_RUN_R2
#define GIRLNINJA_STAND_R3 GIRLNINJA_RUN_R3
#define GIRLNINJA_STAND_R4 GIRLNINJA_RUN_R4

#define GIRLNINJA_CRAWL_FRAMES 1
#define GIRLNINJA_CRAWL_R0 5211
#define GIRLNINJA_CRAWL_R1 GIRLNINJA_CRAWL_R0 + (GIRLNINJA_CRAWL_FRAMES * 1)
#define GIRLNINJA_CRAWL_R2 GIRLNINJA_CRAWL_R0 + (GIRLNINJA_CRAWL_FRAMES * 2)
#define GIRLNINJA_CRAWL_R3 GIRLNINJA_CRAWL_R0 + (GIRLNINJA_CRAWL_FRAMES * 3)
#define GIRLNINJA_CRAWL_R4 GIRLNINJA_CRAWL_R0 + (GIRLNINJA_CRAWL_FRAMES * 4)

#define GIRLNINJA_THROW_FRAMES 3
#define GIRLNINJA_THROW_R0 5246
#define GIRLNINJA_THROW_R1 GIRLNINJA_THROW_R0 + (GIRLNINJA_THROW_FRAMES * 1)
#define GIRLNINJA_THROW_R2 GIRLNINJA_THROW_R0 + (GIRLNINJA_THROW_FRAMES * 2)

// don't have rotations for pain frames currently

#if 1
#define GIRLNINJA_PAIN_FRAMES 1
#define GIRLNINJA_PAIN_R0 5192
#define GIRLNINJA_PAIN_R1 GIRLNINJA_PAIN_R0
#define GIRLNINJA_PAIN_R2 GIRLNINJA_PAIN_R0
#define GIRLNINJA_PAIN_R3 GIRLNINJA_PAIN_R0
#define GIRLNINJA_PAIN_R4 GIRLNINJA_PAIN_R0
#endif

#define GIRLNINJA_JUMP_FRAMES 4
#define GIRLNINJA_JUMP_R0 5226
#define GIRLNINJA_JUMP_R1 GIRLNINJA_JUMP_R0 + (GIRLNINJA_JUMP_FRAMES * 1)
#define GIRLNINJA_JUMP_R2 GIRLNINJA_JUMP_R0 + (GIRLNINJA_JUMP_FRAMES * 2)
#define GIRLNINJA_JUMP_R3 GIRLNINJA_JUMP_R0 + (GIRLNINJA_JUMP_FRAMES * 3)
#define GIRLNINJA_JUMP_R4 GIRLNINJA_JUMP_R0 + (GIRLNINJA_JUMP_FRAMES * 4)

#define GIRLNINJA_FALL_R0 GIRLNINJA_JUMP_R0+2
#define GIRLNINJA_FALL_R1 GIRLNINJA_JUMP_R1+2
#define GIRLNINJA_FALL_R2 GIRLNINJA_JUMP_R2+2
#define GIRLNINJA_FALL_R3 GIRLNINJA_JUMP_R3+2
#define GIRLNINJA_FALL_R4 GIRLNINJA_JUMP_R4+2

#define GIRLNINJA_LAND_R0 GIRLNINJA_JUMP_R0+3
#define GIRLNINJA_LAND_R1 GIRLNINJA_JUMP_R1+3
#define GIRLNINJA_LAND_R2 GIRLNINJA_JUMP_R2+3
#define GIRLNINJA_LAND_R3 GIRLNINJA_JUMP_R3+3
#define GIRLNINJA_LAND_R4 GIRLNINJA_JUMP_R4+3

#define GIRLNINJA_KNEEL_R0 GIRLNINJA_CRAWL_R0
#define GIRLNINJA_KNEEL_R1 GIRLNINJA_CRAWL_R1
#define GIRLNINJA_KNEEL_R2 GIRLNINJA_CRAWL_R2
#define GIRLNINJA_KNEEL_R3 GIRLNINJA_CRAWL_R3
#define GIRLNINJA_KNEEL_R4 GIRLNINJA_CRAWL_R4

#define GIRLNINJA_FIRE_FRAMES 2
#define GIRLNINJA_FIRE_R0 5182
#define GIRLNINJA_FIRE_R1 GIRLNINJA_FIRE_R0 + (GIRLNINJA_FIRE_FRAMES * 1)
#define GIRLNINJA_FIRE_R2 GIRLNINJA_FIRE_R0 + (GIRLNINJA_FIRE_FRAMES * 2)
#define GIRLNINJA_FIRE_R3 GIRLNINJA_FIRE_R0 + (GIRLNINJA_FIRE_FRAMES * 3)
#define GIRLNINJA_FIRE_R4 GIRLNINJA_FIRE_R0 + (GIRLNINJA_FIRE_FRAMES * 4)

#define GIRLNINJA_STAB_FRAMES 1
#define GIRLNINJA_STAB_R0 5206
#define GIRLNINJA_STAB_R1 GIRLNINJA_STAB_R0 + (GIRLNINJA_STAB_FRAMES * 1)
#define GIRLNINJA_STAB_R2 GIRLNINJA_STAB_R0 + (GIRLNINJA_STAB_FRAMES * 2)
#define GIRLNINJA_STAB_R3 GIRLNINJA_STAB_R0 + (GIRLNINJA_STAB_FRAMES * 3)
#define GIRLNINJA_STAB_R4 GIRLNINJA_STAB_R0 + (GIRLNINJA_STAB_FRAMES * 4)

#define GIRLNINJA_DIE 5197
#define GIRLNINJA_DEAD GIRLNINJA_DIE+8

#define GIRLNINJA_SLICED 4227
#define GIRLNINJA_DEAD_SLICED GIRLNINJA_SLICED+9

//////////////////////
//
// ZILLA
//
//////////////////////

#define ZILLA_RUN_FRAMES 4
#define ZILLA_RUN_R0 5426
#define ZILLA_RUN_R1 ZILLA_RUN_R0 - (ZILLA_RUN_FRAMES * 1)
#define ZILLA_RUN_R2 ZILLA_RUN_R0 - (ZILLA_RUN_FRAMES * 2)
#define ZILLA_RUN_R3 ZILLA_RUN_R0 - (ZILLA_RUN_FRAMES * 3)
#define ZILLA_RUN_R4 ZILLA_RUN_R0 - (ZILLA_RUN_FRAMES * 4)

#define ZILLA_PAIN_FRAMES 1
#define ZILLA_PAIN_R0 5524
#define ZILLA_PAIN_R1 ZILLA_PAIN_R0 - (ZILLA_PAIN_FRAMES * 1)
#define ZILLA_PAIN_R2 ZILLA_PAIN_R0 - (ZILLA_PAIN_FRAMES * 2)
#define ZILLA_PAIN_R3 ZILLA_PAIN_R0 - (ZILLA_PAIN_FRAMES * 3)
#define ZILLA_PAIN_R4 ZILLA_PAIN_R0 - (ZILLA_PAIN_FRAMES * 4)

#define ZILLA_ROCKET_FRAMES 4
#define ZILLA_ROCKET_R0 5446
#define ZILLA_ROCKET_R1 ZILLA_ROCKET_R0 - (ZILLA_ROCKET_FRAMES * 1)
#define ZILLA_ROCKET_R2 ZILLA_ROCKET_R0 - (ZILLA_ROCKET_FRAMES * 2)
#define ZILLA_ROCKET_R3 ZILLA_ROCKET_R0 - (ZILLA_ROCKET_FRAMES * 3)
#define ZILLA_ROCKET_R4 ZILLA_ROCKET_R0 - (ZILLA_ROCKET_FRAMES * 4)

#define ZILLA_RAIL_FRAMES 4
#define ZILLA_RAIL_R0 5466
#define ZILLA_RAIL_R1 ZILLA_RAIL_R0 - (ZILLA_RAIL_FRAMES * 1)
#define ZILLA_RAIL_R2 ZILLA_RAIL_R0 - (ZILLA_RAIL_FRAMES * 2)
#define ZILLA_RAIL_R3 ZILLA_RAIL_R0 - (ZILLA_RAIL_FRAMES * 3)
#define ZILLA_RAIL_R4 ZILLA_RAIL_R0 - (ZILLA_RAIL_FRAMES * 4)

#define ZILLA_SHOOT_FRAMES 4
#define ZILLA_SHOOT_R0 5506
#define ZILLA_SHOOT_R1 ZILLA_SHOOT_R0 - (ZILLA_SHOOT_FRAMES * 1)
#define ZILLA_SHOOT_R2 ZILLA_SHOOT_R0 - (ZILLA_SHOOT_FRAMES * 2)
#define ZILLA_SHOOT_R3 ZILLA_SHOOT_R0 - (ZILLA_SHOOT_FRAMES * 3)
#define ZILLA_SHOOT_R4 ZILLA_SHOOT_R0 - (ZILLA_SHOOT_FRAMES * 4)

#define ZILLA_RECHARGE_FRAMES 4
#define ZILLA_RECHARGE_R0 5486
#define ZILLA_RECHARGE_R1 ZILLA_RECHARGE_R0 - (ZILLA_RECHARGE_FRAMES * 1)
#define ZILLA_RECHARGE_R2 ZILLA_RECHARGE_R0 - (ZILLA_RECHARGE_FRAMES * 2)
#define ZILLA_RECHARGE_R3 ZILLA_RECHARGE_R0 - (ZILLA_RECHARGE_FRAMES * 3)
#define ZILLA_RECHARGE_R4 ZILLA_RECHARGE_R0 - (ZILLA_RECHARGE_FRAMES * 4)

#define ZILLA_DIE 5510
#define ZILLA_DEAD 5518

////////////////////////////////////
#define TRASHCAN 2540

#define SCROLL 516
#define SCROLL_FIRE 524

#define FLOORBLOOD1 389

#endif


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

This file is part of Shadow Warrior version 1.2

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

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

See the GNU General Public License for more details.

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

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

#include "keys.h"
#include "game.h"
#include "tags.h"
#include "names2.h"
#include "network.h"
#include "pal.h"
#include "demo.h"

#include "weapon.h"
#include "text.h"
#include "menus.h"

/*
SYNC BUG NOTES:

    1.  Look at Prediction code first when player movement is involved.  If the
    prediction code changes any variable not in the Player or Players
    Sprite/User structure that effects movement then there will be a Out Of Sync
    problem.

    EXAMPLE:  Prediction player was updating a sop->drive_oangvel making it
    invalid for movement.  Look at DoPlayerBoatTurn for comment.

    2.  Changing movement variables in the draw code.  Because the draw code is
    called at a variable rate this don't work.  This includes using RANDOM_RANGE
    or RANDOM_P2 in the draw code.  This updates the random seed variable and is
    only for movement code.  Use STD_RANDOM_RANGE for draw code.

    3.  Plain old bugs such as using uninitialized local variables.

*/

//#undef MAXSYNCBYTES
//#define MAXSYNCBYTES 16
static uint8_t tempbuf[576], packbuf[576];
int PlayClock;
extern SWBOOL PauseKeySet;
extern char CommPlayerName[32];

gNET gNet;
extern short PlayerQuitMenuLevel;
extern SWBOOL QuitFlag;

//#define NET_DEBUG_MSGS

#define TIMERUPDATESIZ 32

//SW_PACKET fsync;

//Local multiplayer variables
// should move this to a local scope of faketimerhandler - do it when able to test
SW_PACKET loc;

//SW_PACKET oloc;

SWBOOL ready2send = 0;

SWBOOL CommEnabled = FALSE;
uint8_t CommPlayers = 0;
int movefifoplc, movefifosendplc; //, movefifoend[MAX_SW_PLAYERS];
unsigned int MoveThingsCount;

//int myminlag[MAX_SW_PLAYERS];
int mymaxlag, otherminlag, bufferjitter = 1;
extern char sync_first[MAXSYNCBYTES][60];
extern int sync_found;

//
// Tic Duplication - so you can move multiple times per packet
//
typedef struct
{
    int32_t vel;
    int32_t svel;
    fix16_t q16angvel;
    fix16_t q16aimvel;
    fix16_t q16ang;
    fix16_t q16horiz;
    int32_t bits;
} SW_AVERAGE_PACKET;

int MovesPerPacket = 1;
SW_AVERAGE_PACKET AveragePacket;

// GAME.C sync state variables
uint8_t syncstat[MAXSYNCBYTES];
//int syncvalhead[MAX_SW_PLAYERS];
int syncvaltail, syncvaltottail;
void GetSyncInfoFromPacket(uint8_t *packbuf, int packbufleng, int *j, int otherconnectindex);

// when you set totalclock to 0 also set this one
int ototalclock;
int smoothratio;
int save_totalclock;

// must start out as 0

SWBOOL GamePaused = FALSE;
SWBOOL NetBroadcastMode = TRUE;
SWBOOL NetModeOverride = FALSE;

void netsendpacket(int ind, uint8_t* buf, int len)
{
    uint8_t bbuf[sizeof(packbuf) + sizeof(PACKET_PROXY)];
    PACKET_PROXYp prx = (PACKET_PROXYp)bbuf;

    // send via master if in M/S mode and we are not the master, and the recipient is not the master and not ourselves
    if (!NetBroadcastMode && myconnectindex != connecthead && ind != myconnectindex && ind != connecthead)
    {
        if ((unsigned)len > sizeof(packbuf))
        {
            buildprintf("netsendpacket(): packet length > %d!\n",(int)sizeof(packbuf));
            len = sizeof(packbuf);
        }

#ifdef NET_DEBUG_MSGS
        buildprintf("netsendpacket() sends proxy to %d\nPlayerIndex=%d Contents:",connecthead,ind);
        for (int i=0; i<len; i++)
            buildprintf(" %02x", buf[i]);
        buildputs("\n");
#endif

        prx->PacketType = PACKET_TYPE_PROXY;
        prx->PlayerIndex = (uint8_t)ind;
        memcpy(&prx[1], buf, len);  // &prx[1] == (char*)prx + sizeof(PACKET_PROXY)
        len += sizeof(PACKET_PROXY);

        sendpacket(connecthead, bbuf, len);
        return;
    }

    sendpacket(ind, buf, len);

#ifdef NET_DEBUG_MSGS
    buildprintf("netsendpacket() sends normal to %d\nContents:",ind);
    for (int i=0; i<len; i++)
        buildprintf(" %02x", buf[i]);
    buildputs("\n");
#endif
}

void netbroadcastpacket(uint8_t* buf, int len)
{
    int i;
    uint8_t bbuf[sizeof(packbuf) + sizeof(PACKET_PROXY)];
    PACKET_PROXYp prx = (PACKET_PROXYp)bbuf;

    // broadcast via master if in M/S mode and we are not the master
    if (!NetBroadcastMode && myconnectindex != connecthead)
    {
        if ((unsigned)len > sizeof(packbuf))
        {
            buildprintf("netbroadcastpacket(): packet length > %d!\n",(int)sizeof(packbuf));
            len = sizeof(packbuf);
        }

#ifdef NET_DEBUG_MSGS
        buildprintf("netbroadcastpacket() sends proxy to %d\nPlayerIndex=255 Contents:",connecthead);
        for (i=0; i<len; i++)
            buildprintf(" %02x", buf[i]);
        buildputs("\n");
#endif

        prx->PacketType = PACKET_TYPE_PROXY;
        prx->PlayerIndex = (uint8_t)(-1);
        memcpy(&prx[1], buf, len);
        len += sizeof(PACKET_PROXY);

        sendpacket(connecthead, bbuf, len);
        return;
    }

    for (i = connecthead; i >= 0; i = connectpoint2[i])
    {
        if (i == myconnectindex) continue;
        sendpacket(i, buf, len);
#ifdef NET_DEBUG_MSGS
        buildprintf("netsendpacket() sends normal to %d\n",i);
#endif
    }
#ifdef NET_DEBUG_MSGS
    buildputs("Contents:");
    for (i=0; i<len; i++)
        buildprintf(" %02x", buf[i]);
    buildputs("\n");
#endif
}

int netgetpacket(int *ind, uint8_t* buf)
{
    int i;
    int len;
    PACKET_PROXYp prx;

    len = getpacket(ind, buf);
    if ((unsigned)len < sizeof(PACKET_PROXY) || buf[0] != PACKET_TYPE_PROXY)
    {
#ifdef NET_DEBUG_MSGS
        if (len > 0)
        {
            buildprintf("netgetpacket() gets normal from %d\nContents:",*ind);
            for (i=0; i<len; i++)
                buildprintf(" %02x", buf[i]);
            buildputs("\n");
        }
#endif
        return len;
    }

    prx = (PACKET_PROXYp)buf;

#ifdef NET_DEBUG_MSGS
    buildprintf("netgetpacket() got proxy from %d\nPlayerIndex=%d Contents:",*ind,prx->PlayerIndex);
    for (i=0; i<len-(int)sizeof(PACKET_PROXY); i++)
        buildprintf(" %02x", *(((char *)&prx[1])+i));
    buildputs("\n");
#endif

    if (myconnectindex == connecthead)
    {
        // I am the master

        if (prx->PlayerIndex == (uint8_t)(-1))
        {
            // broadcast

            // Rewrite the player index to be the sender's connection number
            prx->PlayerIndex = (uint8_t)*ind;

            // Transmit to all the other players except ourselves and the sender
            for (i = connecthead; i >= 0; i = connectpoint2[i])
            {
                if (i == myconnectindex || i == *ind) continue;
#ifdef NET_DEBUG_MSGS
                buildprintf("netgetpacket(): distributing to %d\n", i);
#endif
                sendpacket(i, buf, len);
            }

            // Return the packet payload to the caller
            len -= sizeof(PACKET_PROXY);
            memmove(buf, &prx[1], len);
            return len;
        }
        else
        {
            // proxy send to a specific player

            i = prx->PlayerIndex;

            // Rewrite the player index to be the sender's connection number
            prx->PlayerIndex = (uint8_t)*ind;

            // Transmit to the intended recipient
            if (i == myconnectindex)
            {
                len -= sizeof(PACKET_PROXY);
                memmove(buf, &prx[1], len);
                return len;
            }

#ifdef NET_DEBUG_MSGS
            buildprintf("netgetpacket(): forwarding to %d\n", i);
#endif
            sendpacket(i, buf, len);
            return 0;   // nothing for us to do
        }
    }
    else if (*ind == connecthead)
    {
        // I am a slave, and the proxy message came from the master
        *ind = prx->PlayerIndex;
        len -= sizeof(PACKET_PROXY);
        memmove(buf, &prx[1], len);
        return len;
    }
    else
    {
        buildprintf("netgetpacket(): Got a proxy message from %d instead of %d\n",*ind,connecthead);
    }
    return 0;
}

int EncodeBits(SW_PACKET *pak, SW_PACKET *old_pak, uint8_t* buf)
{
    uint8_t* base_ptr = buf;
    unsigned i;

    // skipping the bits field sync test fake byte (Ed. Ken)
    *buf = 0;
    buf++;

    // TODO: Properly copy the values in a cross-platform manner
    if (pak->vel != old_pak->vel)
    {
        *((short *)buf) = pak->vel;
        buf += sizeof(pak->vel);
        SET(*base_ptr, BIT(0));
    }

    if (pak->svel != old_pak->svel)
    {
        *((short *)buf) = pak->svel;
        buf += sizeof(pak->svel);
        SET(*base_ptr, BIT(1));
    }

    if ((pak->q16angvel != old_pak->q16angvel) || (pak->q16ang != old_pak->q16ang))
    {
        *((fix16_t *)buf) = pak->q16angvel;
        buf += sizeof(pak->q16angvel);
        *((fix16_t *)buf) = pak->q16ang;
        buf += sizeof(pak->q16ang);
        SET(*base_ptr, BIT(2));
    }

    if ((pak->q16aimvel != old_pak->q16aimvel) || (pak->q16horiz != old_pak->q16horiz))
    {
        *((fix16_t *)buf) = pak->q16aimvel;
        buf += sizeof(pak->q16aimvel);
        *((fix16_t *)buf) = pak->q16horiz;
        buf += sizeof(pak->q16horiz);
        SET(*base_ptr, BIT(3));
    }

    //won't work if > 4 bytes
    for (i = 0; i < sizeof(pak->bits); i++)
    {
        if (TEST(pak->bits ^ old_pak->bits, 0xff<<(i<<3)))
        {
            *buf = (pak->bits>>(i<<3));
            buf++;
            SET(*base_ptr, BIT(i+4));
        }
    }

    return buf - base_ptr;
}

int DecodeBits(SW_PACKET *pak, SW_PACKET *old_pak, uint8_t* buf)
{
    uint8_t* base_ptr = buf;
    unsigned i;

    // skipping the bits field sync test fake byte (Ed. Ken)
    buf++;

    *pak = *old_pak;

    // TODO: Properly copy the values in a cross-platform manner
    if (TEST(*base_ptr, BIT(0)))
    {
        pak->vel = *(short *)buf;
        buf += sizeof(pak->vel);
    }

    if (TEST(*base_ptr, BIT(1)))
    {
        pak->svel = *(short *)buf;
        buf += sizeof(pak->svel);
    }

    if (TEST(*base_ptr, BIT(2)))
    {
        pak->q16angvel = *(fix16_t *)buf;
        buf += sizeof(pak->q16angvel);
        pak->q16ang = *(fix16_t *)buf;
        buf += sizeof(pak->q16ang);
    }

    if (TEST(*base_ptr, BIT(3)))
    {
        pak->q16aimvel = *(fix16_t *)buf;
        buf += sizeof(pak->q16aimvel);
        pak->q16horiz = *(fix16_t *)buf;
        buf += sizeof(pak->q16horiz);
    }

    //won't work if > 4 bytes
    for (i = 0; i < sizeof(pak->bits); i++)
    {
        if (TEST(*base_ptr, BIT(i+4)))
        {
            RESET(pak->bits, 0xff<<(i<<3));
            SET(pak->bits, ((int)(*buf))<<(i<<3));
            buf++;
        }
    }

    return buf - base_ptr;
}

void
PauseGame(void)
{
    if (PauseKeySet)
        return;

    if (DemoPlaying || DemoRecording)
        return;

    if (GamePaused)
        return;

    if (numplayers < 2)
        GamePaused = TRUE;
}

void
ResumeGame(void)
{
    if (PauseKeySet)
        return;

    if (DemoPlaying || DemoRecording)
        return;

    if (numplayers < 2)
        GamePaused = FALSE;
}

void
PauseAction(void)
{
    ready2send = 0;
    save_totalclock = (int32_t) totalclock;
}

void
ResumeAction(void)
{
    ready2send = 1;
    totalclock = save_totalclock;
}

void
SW_SendMessage(short pnum, const char *text)
{
    if (!CommEnabled)
        return;

    tempbuf[0] = PACKET_TYPE_MESSAGE;
    strcpy((char *)&tempbuf[1], text);
    netsendpacket(pnum, tempbuf, strlen(text) + 2);
}

void
InitNetPlayerOptions(void)
{
//    short pnum;
    PLAYERp pp = Player + myconnectindex;
    PACKET_OPTIONS p;

    // if you don't have a name :(
    if (!CommPlayerName[0])
        sprintf(CommPlayerName, "PLAYER %d", myconnectindex + 1);

    Bstrupr(CommPlayerName);
    strcpy(pp->PlayerName, CommPlayerName);

    // myconnectindex palette
    pp->TeamColor = gs.NetColor;
    pp->SpriteP->pal = PALETTE_PLAYER0 + pp->TeamColor;
    User[pp->SpriteP - sprite]->spal = pp->SpriteP->pal;

    if (CommEnabled)
    {
        p.PacketType = PACKET_TYPE_PLAYER_OPTIONS;
        p.AutoRun = gs.AutoRun;
        p.Color = gs.NetColor;
        strcpy(p.PlayerName, CommPlayerName);

        //TRAVERSE_CONNECT(pnum)
        {
            //if (pnum != myconnectindex)
            {
                //netsendpacket(pnum, (char *)(&p), sizeof(p));
                netbroadcastpacket((uint8_t*)(&p), sizeof(p));
            }
        }
    }
}

void
SendMulitNameChange(char *new_name)
{
//    short pnum;
    PLAYERp pp = Player + myconnectindex;
    PACKET_NAME_CHANGE p;

    if (!CommEnabled)
        return;

    Bstrupr(new_name);
    strcpy(pp->PlayerName, new_name);
    strcpy(CommPlayerName, new_name);
    SetRedrawScreen(pp);

    //TRAVERSE_CONNECT(pnum)
    {
        //if (pnum != myconnectindex)
        {
            p.PacketType = PACKET_TYPE_NAME_CHANGE;
            strcpy(p.PlayerName, pp->PlayerName);
            //netsendpacket(pnum, (char *)(&p), sizeof(p));
            netbroadcastpacket((uint8_t*)(&p), sizeof(p));
        }
    }
}

void
SendVersion(int version)
{
//    short pnum;
    PLAYERp pp = Player + myconnectindex;
    PACKET_VERSION p;

    if (!CommEnabled)
        return;

    pp->PlayerVersion = version;

    //TRAVERSE_CONNECT(pnum)
    {
        //if (pnum != myconnectindex)
        {
            p.PacketType = PACKET_TYPE_VERSION;
            p.Version = version;
            //netsendpacket(pnum, (char *)(&p), sizeof(p));
            netbroadcastpacket((uint8_t*)(&p), sizeof(p));
        }
    }
}

void
CheckVersion(int GameVersion)
{
    short pnum;
#define VERSION_MSG "You cannot play with different versions!"

    if (!CommEnabled)
        return;

    TRAVERSE_CONNECT(pnum)
    {
        if (pnum != myconnectindex)
        {
            if (GameVersion != Player[pnum].PlayerVersion)
            {
                buildprintf("CheckVersion(): player %d has version %d, expecting %d\n",
                            pnum, Player[pnum].PlayerVersion, GameVersion);

                adduserquote(VERSION_MSG);
                adduserquote(VERSION_MSG);
                adduserquote(VERSION_MSG);
                adduserquote(VERSION_MSG);
                adduserquote(VERSION_MSG);
                adduserquote(VERSION_MSG);

                if (!Player[pnum].PlayerVersion)
                {
                    SW_SendMessage(pnum, VERSION_MSG);
                    SW_SendMessage(pnum, VERSION_MSG);
                    SW_SendMessage(pnum, VERSION_MSG);
                    SW_SendMessage(pnum, VERSION_MSG);
                    SW_SendMessage(pnum, VERSION_MSG);
                    SW_SendMessage(pnum, VERSION_MSG);
                }
            }
        }
    }
}

void
Connect(void)
{
    if (CommEnabled)
    {
#if 0
        int x1, x2, y1, y2;
        int screensize = xdim;
        extern short BorderTest[];

        // put up a tile
        x1 = (xdim >> 1) - (screensize >> 1);
        x2 = x1 + screensize - 1;
        y1 = ((ydim) >> 1) - (((screensize * (ydim)) / xdim) >> 1);
        y2 = y1 + ((screensize * (ydim)) / xdim) - 1;
        rotatespritetile(BorderTest[gs.BorderTile], 0, x1, y1, x2, y2, 0);
        nextpage();
#endif

        screenpeek = myconnectindex;
    }

    //InitTimingVars();                   // resettiming();
}

SWBOOL (*wfe_ExitCallback)(void);

void
waitforeverybody(void)
{
    int i, size = 1;

    if (!CommEnabled)
        return;

    buildprintf("waitforeverybody() #%d\n", Player[myconnectindex].playerreadyflag + 1);

    //tenDbLprintf(gTenLog, 3, "in w4e");
    //tenDbFlushLog(gTenLog);
    tempbuf[0] = PACKET_TYPE_PLAYER_READY;
#ifdef DEBUG
    tempbuf[1] = Player[myconnectindex].playerreadyflag + 1;
    size++;
#endif
    // if we're a peer or slave, not a master
    if (!NetBroadcastMode && myconnectindex != connecthead)
        netsendpacket(connecthead, tempbuf, size);
    else if (NetBroadcastMode)
        netbroadcastpacket(tempbuf, size);

#if 0
    for (i = connecthead; i >= 0; i = connectpoint2[i])
    {
        if (i != myconnectindex)
        {
            DSPRINTF(ds,"Ready packet sent to %d", i);
            DebugWriteString(ds);
        }
    }
#endif

    //KEY_PRESSED(KEYSC_ESC) = FALSE;
    Player[myconnectindex].playerreadyflag++;

    while (TRUE)
    {
        if (PlayerQuitMenuLevel >= 0)
        {
            //DSPRINTF(ds,"%d, Player Quit Menu Level %d", myconnectindex, PlayerQuitMenuLevel);
            //DebugWriteString(ds);

            MenuCommPlayerQuit(PlayerQuitMenuLevel);
            PlayerQuitMenuLevel = -1;
        }

        handleevents();
        getpackets();

        if (quitevent || (wfe_ExitCallback && wfe_ExitCallback()))
        {
            // allow exit
            //if (KEY_PRESSED(KEYSC_ESC))
            {
//                short pnum;
                //TRAVERSE_CONNECT(pnum)
                {
                    //if (pnum != myconnectindex)
                    {
                        tempbuf[0] = PACKET_TYPE_MENU_LEVEL_QUIT;
                        //netsendpacket(pnum, tempbuf, 1);
                        netbroadcastpacket(tempbuf, 1);
                    }
                }

                TerminateGame();
                exit(0);
            }
        }

#if 0
        for (i = connecthead; i >= 0; i = connectpoint2[i])
        {
            DSPRINTF(ds,"myindex %d, myready %d, Player %d, Ready %d", myconnectindex, Player[myconnectindex].playerreadyflag, i, Player[i].playerreadyflag);
            DebugWriteString(ds);
        }
#endif

        for (i = connecthead; i >= 0; i = connectpoint2[i])
        {
            if (Player[i].playerreadyflag < Player[myconnectindex].playerreadyflag)
                break;
            if ((!NetBroadcastMode) && (myconnectindex != connecthead)) { i = -1; break; } //slaves in M/S mode only wait for master
        }

        if (i < 0)
        {
            // master sends ready packet once it hears from all slaves
            if (!NetBroadcastMode && myconnectindex == connecthead)
                netbroadcastpacket(tempbuf, size);
            return;
        }
    }
}

SWBOOL MyCommPlayerQuit(void)
{
    PLAYERp pp;
    short i;
    short prev_player = 0;
    short found = FALSE;
    short quit_player_index = 0;

    TRAVERSE_CONNECT(i)
    {
        if (TEST_SYNC_KEY(Player + i, SK_QUIT_GAME))
        {
            if (!NetBroadcastMode && i == connecthead)
            {
                // If it's the master, it should first send quit message to the slaves.
                // Each slave should automatically quit after receiving the message.
                if (i == myconnectindex)
                    continue;
                QuitFlag = TRUE;
                ready2send = 0;
                return TRUE;
            }

            found = TRUE;

            quit_player_index = i;

            if (i != myconnectindex)
            {
                sprintf(ds,"%s has quit the game.",Player[i].PlayerName);
                adduserquote(ds);
            }
        }
    }

    if (found)
    {
        TRAVERSE_CONNECT(i)
        {
            pp = Player + i;

            if (i == quit_player_index)
            {
                PLAYERp qpp = Player + quit_player_index;
                SET(qpp->SpriteP->cstat, CSTAT_SPRITE_INVISIBLE);
                RESET(qpp->SpriteP->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN|CSTAT_SPRITE_BLOCK_MISSILE);
                InitBloodSpray(qpp->PlayerSprite,TRUE,-2);
                InitBloodSpray(qpp->PlayerSprite,FALSE,-2);
                qpp->SpriteP->ang = NORM_ANGLE(qpp->SpriteP->ang + 1024);
                InitBloodSpray(qpp->PlayerSprite,FALSE,-1);
                InitBloodSpray(qpp->PlayerSprite,TRUE,-1);
            }

            // have to reorder the connect list
            if (!TEST_SYNC_KEY(pp, SK_QUIT_GAME))
            {
                prev_player = i;
                continue;
            }

            // if I get my own messages get out to DOS QUICKLY!!!
            if (i == myconnectindex)
            {
                QuitFlag = TRUE;
                ready2send = 0;
                return TRUE;
            }

            // for COOP mode
            if (screenpeek == i)
            {
                screenpeek = connectpoint2[i];
                if (screenpeek < 0)
                    screenpeek = connecthead;
            }

            DSPRINTF(ds,"MyCommPlayerQuit %d", quit_player_index);
            DebugWriteString(ds);

            if (i == connecthead)
                connecthead = connectpoint2[connecthead];
            else
                connectpoint2[prev_player] = connectpoint2[i];

            numplayers--;
            CommPlayers--;
        }
    }

    return FALSE;
}

SWBOOL MenuCommPlayerQuit(short quit_player)
{
    short i;
    short prev_player = 0;
    short pnum;

    // tell everyone else you left the game
    TRAVERSE_CONNECT(pnum)
    {
        if (pnum != quit_player)
        {
            sprintf(ds,"%s has quit the game.",Player[myconnectindex].PlayerName);
            SW_SendMessage(pnum, ds);
        }
    }

    TRAVERSE_CONNECT(i)
    {
        // have to reorder the connect list
        if (i != quit_player)
        {
            prev_player = i;
            continue;
        }

        // for COOP mode
        if (screenpeek == i)
        {
            screenpeek = connectpoint2[i];
            if (screenpeek < 0)
                screenpeek = connecthead;
        }

        DSPRINTF(ds,"MenuPlayerQuit %d", quit_player);
        DebugWriteString(ds);

        if (i == connecthead)
            connecthead = connectpoint2[connecthead];
        else
            connectpoint2[prev_player] = connectpoint2[i];

        numplayers--;
        CommPlayers--;
    }

    return FALSE;
}

void ErrorCorrectionQuit(void)
{
    int oldtotalclock;
    short j;

    if (CommPlayers > 1)
    {
        for (j = 0; j < MAX_SW_PLAYERS; j++)
        {
            oldtotalclock = (int32_t) totalclock;
            while (totalclock < oldtotalclock + synctics)
            {
                handleevents();
                getpackets();
            }

            tempbuf[0] = PACKET_TYPE_NULL_PACKET;
            netbroadcastpacket(tempbuf, 1);
        }
    }
}

void
InitNetVars(void)
{
    short pnum;
    PLAYERp pp;

    memset(&loc, 0, sizeof(loc));

    TRAVERSE_CONNECT(pnum)
    {
        pp = Player + pnum;
        pp->movefifoend = 0;
        Player[pnum].syncvalhead = 0;
        memset(pp->inputfifo,0,sizeof(pp->inputfifo));
    }
    movefifoplc = 0;
    movefifosendplc = 0;
    syncvaltail = 0;
    syncvaltottail = 0;
    predictmovefifoplc = 0;

    memset(&syncstat, 0, sizeof(syncstat));
    syncstate = 0;
    memset(sync_first, 0, sizeof(sync_first));
    sync_found = FALSE;

    TRAVERSE_CONNECT(pnum)
    {
        Player[pnum].myminlag = 0;
    }

    otherminlag = mymaxlag = 0;
}

void
InitTimingVars(void)
{
    PlayClock = 0;

    // resettiming();
    totalsynctics = 0;
    totalclock = 0;
    ototalclock = 0;
    randomseed = 17L;

    MoveSkip8 = 2;
    MoveSkip2 = 0;
    MoveSkip4 = 1;                      // start slightly offset so these
    // don't move the same
    // as the Skip2's
    MoveThingsCount = 0;

    // CTW REMOVED
    //if (gTenActivated)
    //	tenResetClock();
    // CTW REMOVED END

}

void
AddSyncInfoToPacket(int *j)
{
    int sb;
    int count = 0;

    // sync testing
    while (Player[myconnectindex].syncvalhead != syncvaltail && count++ < 4)
    {
        for (sb = 0; sb < NumSyncBytes; sb++)
            packbuf[(*j)++] = Player[myconnectindex].syncval[syncvaltail & (SYNCFIFOSIZ - 1)][sb];

        syncvaltail++;
    }
}

void faketimerhandler(void) { ; }

void
UpdateInputs(void)
{
    int i, j, k;
    PLAYERp pp;
    void getinput(SW_PACKET *, SWBOOL);
    extern SWBOOL BotMode;

    ototalclock += synctics;

    getpackets();

// TENSW: this way we are guaranteed that the most advanced player is no more
// than 200 frames ahead of the most laggy. We're more healthy if the queue
// doesn't overflow, that's for sure.
    if (Player[myconnectindex].movefifoend - movefifoplc >= 100)
        return;

    getinput(&loc, FALSE);

    AveragePacket.vel += loc.vel;
    AveragePacket.svel += loc.svel;
    AveragePacket.q16angvel += loc.q16angvel;
    AveragePacket.q16aimvel += loc.q16aimvel;
    AveragePacket.q16ang = Player[myconnectindex].camq16ang;
    AveragePacket.q16horiz = Player[myconnectindex].camq16horiz;
    SET(AveragePacket.bits, loc.bits);

    Bmemset(&loc, 0, sizeof(loc));

    pp = Player + myconnectindex;

    if (pp->movefifoend & (MovesPerPacket-1))
    {
        memcpy(&pp->inputfifo[pp->movefifoend & (MOVEFIFOSIZ - 1)],
               &pp->inputfifo[(pp->movefifoend-1) & (MOVEFIFOSIZ - 1)],
               sizeof(SW_PACKET));

        pp->movefifoend++;
        return;
    }

    loc.vel = AveragePacket.vel / MovesPerPacket;
    loc.svel = AveragePacket.svel / MovesPerPacket;
    loc.q16angvel = fix16_div(AveragePacket.q16angvel, fix16_from_int(MovesPerPacket));
    loc.q16aimvel = fix16_div(AveragePacket.q16aimvel, fix16_from_int(MovesPerPacket));
    loc.q16ang = AveragePacket.q16ang;
    loc.q16horiz = AveragePacket.q16horiz;
    loc.bits = AveragePacket.bits;

    memset(&AveragePacket, 0, sizeof(AveragePacket));

    pp->inputfifo[Player[myconnectindex].movefifoend & (MOVEFIFOSIZ - 1)] = loc;
    pp->movefifoend++;
    Bmemset(&loc, 0, sizeof(loc));

#if 0
//  AI Bot stuff
    if (numplayers > 1)
    {
        if (gNet.MultiGameType == MULTI_GAME_AI_BOTS)
        {
            for (i=connecthead; i>=0; i=connectpoint2[i])
            {
                if (i != myconnectindex)
                {
                    if (BotMode && Player[i].IsAI == 1) // Skip it if this player is not computer controlled!
                    {
                        computergetinput(i,&Player[i].inputfifo[Player[i].movefifoend&(MOVEFIFOSIZ-1)]);
                        Player[i].movefifoend++;
                    }
                }
            }
        }
    }
// AI Bot stuff
#endif

    if (!CommEnabled)
    {
        TRAVERSE_CONNECT(i)
        {
            if (i != myconnectindex)
            {
                if (BotMode && Player[i].IsAI == 1)
                {
                    computergetinput(i,&Player[i].inputfifo[Player[i].movefifoend&(MOVEFIFOSIZ-1)]);
                }
                else
                    memset(&Player[i].inputfifo[Player[i].movefifoend & (MOVEFIFOSIZ - 1)], 0, sizeof(Player[i].inputfifo[0]));
                Player[i].movefifoend++;
            }
        }
        return;
    }

    TRAVERSE_CONNECT(i)
    {
        if (i != myconnectindex)
        {
            k = (Player[myconnectindex].movefifoend - 1) - Player[i].movefifoend;
            Player[i].myminlag = min(Player[i].myminlag, k);
            mymaxlag = max(mymaxlag, k);
        }
    }

    if (((Player[myconnectindex].movefifoend - 1) & (TIMERUPDATESIZ - 1)) == 0)
    {
        i = mymaxlag - bufferjitter;
        mymaxlag = 0;
        if (i > 0)
            bufferjitter += ((2 + i) >> 2);
        else if (i < 0)
            bufferjitter -= ((2 - i) >> 2);
    }

    // If this isn't the master, and the player decided to quit, leave
    // the game after sending the message. Otherwise, before processing
    // local message with SK_QUIT bit, we may wait in MoveLoop for another
    // message with input from one of the peers, only to never get any,
    // as the peer in question already removed this player from its list.
    if ((NetBroadcastMode || (myconnectindex != connecthead)) &&
        TEST(pp->inputfifo[(pp->movefifoend - 1) & (MOVEFIFOSIZ - 1)].bits, BIT(SK_QUIT_GAME)))
        QuitFlag = TRUE;

    if (NetBroadcastMode)
    {
        packbuf[0] = PACKET_TYPE_BROADCAST;
        j = 1;

        if (((Player[myconnectindex].movefifoend - 1) & (TIMERUPDATESIZ - 1)) == 0 /* CTW REMOVED && !gTenActivated */)
        {
            if (myconnectindex == connecthead)
            {
                for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
                    packbuf[j++] = min(max(Player[i].myminlag, -128), 127);
            }
            else
            {
                i = Player[connecthead].myminlag - otherminlag;
                if (labs(i) > 2)
                {
                    ////DSPRINTF(ds,"lag correction: %d,%d,%d",i,Player[connecthead].myminlag,otherminlag);
                    //MONO_PRINT(ds);

                    if (labs(i) > 8)
                    {
                        if (i < 0)
                            i++;
                        i >>= 1;
                    }
                    else
                    {
                        if (i < 0)
                            i = -1;
                        if (i > 0)
                            i = 1;
                    }
                    totalclock -= synctics * i;
                    otherminlag += i;
                }
            }

            for (i = connecthead; i >= 0; i = connectpoint2[i])
                Player[i].myminlag = 0x7fffffff;
        }

        pp = Player + myconnectindex;

#if !BIT_CODEC
        memcpy(&packbuf[j], &pp->inputfifo[(Player[myconnectindex].movefifoend - 1) & (MOVEFIFOSIZ - 1)], sizeof(SW_PACKET));
        j += sizeof(SW_PACKET);
#else
        j += EncodeBits(&pp->inputfifo[(Player[myconnectindex].movefifoend - 1) & (MOVEFIFOSIZ - 1)],
                        &pp->inputfifo[(Player[myconnectindex].movefifoend - 2) & (MOVEFIFOSIZ - 1)],
                        &packbuf[j]);
#endif

#if SYNC_TEST
        AddSyncInfoToPacket(&j);
#endif

        netbroadcastpacket(packbuf, j);

        return;
    } // NetBroadcastMode

    // SLAVE CODE
    if (myconnectindex != connecthead)  // I am the Slave
    {
        if (((Player[myconnectindex].movefifoend - 1) & (TIMERUPDATESIZ - 1)) == 0)
        {
            i = Player[connecthead].myminlag - otherminlag;
            if (labs(i) > 2)
            {
                if (labs(i) > 8)
                {
                    if (i < 0)
                        i++;
                    i >>= 1;
                }
                else
                {
                    if (i < 0)
                        i = -1;
                    if (i > 0)
                        i = 1;
                }
                totalclock -= synctics * i;
                otherminlag += i;
            }

            for (i = connecthead; i >= 0; i = connectpoint2[i])
            {
                Player[i].myminlag = 0x7fffffff;
            }
        }
        packbuf[0] = PACKET_TYPE_SLAVE_TO_MASTER;
        j = 1;

        pp = Player + myconnectindex;
#if !BIT_CODEC
        memcpy(&packbuf[j], &pp->inputfifo[(pp->movefifoend - 1) & (MOVEFIFOSIZ - 1)], sizeof(SW_PACKET));
        j += sizeof(SW_PACKET);
#else
        j += EncodeBits(&pp->inputfifo[(pp->movefifoend - 1) & (MOVEFIFOSIZ - 1)],
                        &pp->inputfifo[(pp->movefifoend - 2) & (MOVEFIFOSIZ - 1)],
                        &packbuf[j]);
#endif

#if SYNC_TEST
        AddSyncInfoToPacket(&j);
#endif

        netsendpacket(connecthead, packbuf, j);
        return;
    }

    // This allows packet-resends
    //for (i = connecthead; i >= 0; i = connectpoint2[i])
    //    {
    //    if ( /* (!playerquitflag[i]) && */ (Player[i].movefifoend <= movefifosendplc))
    //        {
    //        packbuf[0] = 127;
    //        for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
    //            {
    //             /* if (!playerquitflag[i]) */ sendpacket(i, packbuf, 1);
    //            }
    //        return;
    //        }
    //    }

    // I am MASTER...
    while (1)
    {
        for (i = connecthead; i >= 0; i = connectpoint2[i])
        {
            if (/* (!playerquitflag[i]) && */ (Player[i].movefifoend <= movefifosendplc))
                return;
        }

        packbuf[0] = PACKET_TYPE_MASTER_TO_SLAVE;
        j = 1;

        // Fix timers and buffer/jitter value
        if ((movefifosendplc & (TIMERUPDATESIZ - 1)) == 0)
        {
            for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
            {
                /* if (!playerquitflag[i]) */
                packbuf[j++] = min(max(Player[i].myminlag, -128), 127);
            }

            for (i = connecthead; i >= 0; i = connectpoint2[i])
                Player[i].myminlag = 0x7fffffff;
        }

        for (i = connecthead; i >= 0; i = connectpoint2[i])
        {
            /* if (playerquitflag[i]) continue; */
            pp = Player + i;

#if !BIT_CODEC
            memcpy(&packbuf[j], &pp->inputfifo[movefifosendplc & (MOVEFIFOSIZ - 1)], sizeof(SW_PACKET));
            j += sizeof(SW_PACKET);
#else
            j += EncodeBits(&pp->inputfifo[(movefifosendplc) & (MOVEFIFOSIZ - 1)],
                            &pp->inputfifo[(movefifosendplc - 1) & (MOVEFIFOSIZ - 1)],
                            &packbuf[j]);
#endif
            //pp->movefifoend++;
        }

#if SYNC_TEST
        AddSyncInfoToPacket(&j);
#endif

        for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
        /* if (!playerquitflag[i])*/
        {
            netsendpacket(i, packbuf, j);
            /*
            pp = Player + i;
            if (TEST(pp->inputfifo[movefifosendplc & (MOVEFIFOSIZ - 1)].bits,QUITBIT)
               playerquitflag[i] = 1;
            */
        }
        // Master player should quit only after notifying all peers
        if (TEST(Player[myconnectindex].inputfifo[movefifosendplc & (MOVEFIFOSIZ - 1)].bits, BIT(SK_QUIT_GAME)))
            QuitFlag = TRUE;

        movefifosendplc += MovesPerPacket;
    }
}

void
checkmasterslaveswitch(void)
{
}

void
getpackets(void)
{
    int otherconnectindex, packbufleng;
    int i, j, sb;
    PLAYERp pp;
    SW_PACKET tempinput;

    timerUpdateClock();

    if (!CommEnabled)
        return;

    while ((packbufleng = netgetpacket(&otherconnectindex, packbuf)) > 0)
    {
        switch (packbuf[0])
        {
        case PACKET_TYPE_BROADCAST:
        case SERVER_GENERATED_BROADCAST:
            ////DSPRINTF(ds,"Receive Broadcast %d, ready2send %d",otherconnectindex, ready2send);
            //MONO_PRINT(ds);

            //ASSERT(ready2send);
            //if (!ready2send)
            //    break;

            j = 1;

            if ((Player[otherconnectindex].movefifoend & (TIMERUPDATESIZ - 1)) == 0)
            {
                if (otherconnectindex == connecthead)
                {
                    for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
                    {
                        if (i == myconnectindex)
                            otherminlag = (int)((signed char) packbuf[j]);
                        j++;
                    }
                }
            }

            pp = Player + otherconnectindex;

#if !BIT_CODEC
            memcpy(&pp->inputfifo[pp->movefifoend & (MOVEFIFOSIZ - 1)], &packbuf[j], sizeof(SW_PACKET));
            j += sizeof(SW_PACKET);
#else
            j += DecodeBits(&pp->inputfifo[(pp->movefifoend) & (MOVEFIFOSIZ - 1)],
                            &pp->inputfifo[(pp->movefifoend - 1) & (MOVEFIFOSIZ - 1)],
                            &packbuf[j]);
#endif

            pp->movefifoend++;

            // Packet Duplication
            for (i = 1; i < MovesPerPacket; i++)
            {
                memcpy(
                    &pp->inputfifo[pp->movefifoend & (MOVEFIFOSIZ - 1)],
                    &pp->inputfifo[(pp->movefifoend-1) & (MOVEFIFOSIZ - 1)],
                    sizeof(SW_PACKET));

                pp->movefifoend++;
            }

#if SYNC_TEST
            GetSyncInfoFromPacket(packbuf, packbufleng, &j, otherconnectindex);
#endif

            //DSPRINTF(ds,"Receive packet size %d",j);
            //MONO_PRINT(ds);

            break;

        case PACKET_TYPE_MASTER_TO_SLAVE:
            // Here slave is receiving
            j = 1;

            if ((Player[otherconnectindex].movefifoend & (TIMERUPDATESIZ - 1)) == 0)
            {
                for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
                {
                    // if (playerquitflag[i]) continue;
                    if (i == myconnectindex)
                        otherminlag = (int)((signed char) packbuf[j]);
                    j++;
                }
            }

            for (i = connecthead; i >= 0; i = connectpoint2[i])
            {
                /* if (playerquitflag[i]) continue;) */
                pp = Player + i;

#if !BIT_CODEC
                if (i != myconnectindex)
                    memcpy(&pp->inputfifo[pp->movefifoend++ & (MOVEFIFOSIZ - 1)], &packbuf[j], sizeof(SW_PACKET));
                j += sizeof(SW_PACKET);
#else
                if (i == myconnectindex)
                {
                    j += DecodeBits(&tempinput,
                                    &pp->inputfifo[(pp->movefifoend - 1) & (MOVEFIFOSIZ - 1)],
                                    &packbuf[j]);
                }
                else
                {
                    j += DecodeBits(&pp->inputfifo[(pp->movefifoend) & (MOVEFIFOSIZ - 1)],
                                    &pp->inputfifo[(pp->movefifoend - 1) & (MOVEFIFOSIZ - 1)],
                                    &packbuf[j]);
                    pp->movefifoend++;
                }
#endif
            }

            while (j != packbufleng)
            {
                for (i = connecthead; i >= 0; i = connectpoint2[i])
                {
                    if (i != myconnectindex)
                    {
                        for (sb = 0; sb < NumSyncBytes; sb++)
                        {
                            Player[i].syncval[Player[i].syncvalhead & (SYNCFIFOSIZ - 1)][sb] = packbuf[j + sb];
                        }

                        Player[i].syncvalhead++;
                    }
                }

                j += NumSyncBytes;
            }

#if SYNC_TEST
            GetSyncInfoFromPacket(packbuf, packbufleng, &j, otherconnectindex);
#endif

            for (i=connecthead; i>=0; i=connectpoint2[i])
                if (i != myconnectindex)
                    for (j=1; j<MovesPerPacket; j++)
                    {
                        pp = Player + i;

                        memcpy(
                            &pp->inputfifo[pp->movefifoend & (MOVEFIFOSIZ - 1)],
                            &pp->inputfifo[(pp->movefifoend-1) & (MOVEFIFOSIZ - 1)],
                            sizeof(SW_PACKET));

                        pp->movefifoend++;
                    }

            break;

        case PACKET_TYPE_SLAVE_TO_MASTER:
            // Here master is receiving
            pp = Player + otherconnectindex;
            j = 1;

#if !BIT_CODEC
            memcpy(&pp->inputfifo[Player[otherconnectindex].movefifoend & (MOVEFIFOSIZ - 1)], &packbuf[j], sizeof(SW_PACKET));
            j += sizeof(SW_PACKET);
#else
            j += DecodeBits(&pp->inputfifo[(Player[otherconnectindex].movefifoend) & (MOVEFIFOSIZ - 1)],
                            &pp->inputfifo[(Player[otherconnectindex].movefifoend - 1) & (MOVEFIFOSIZ - 1)],
                            &packbuf[j]);
#endif

            Player[otherconnectindex].movefifoend++;

#if SYNC_TEST
            GetSyncInfoFromPacket(packbuf, packbufleng, &j, otherconnectindex);
#endif

            // Tic duping
            for (i = 1; i < MovesPerPacket; i++)
            {
                memcpy(&pp->inputfifo[(Player[otherconnectindex].movefifoend) & (MOVEFIFOSIZ - 1)],
                       &pp->inputfifo[(Player[otherconnectindex].movefifoend - 1) & (MOVEFIFOSIZ - 1)],
                       sizeof(SW_PACKET));
                Player[otherconnectindex].movefifoend++;
            }

            break;

        case PACKET_TYPE_MESSAGE:
        {
            PLAYERp tp = Player + myconnectindex;

            pp = Player + otherconnectindex;

            PlaySound(DIGI_PMESSAGE,&tp->posx,&tp->posy,&tp->posz,v3df_dontpan);

            memcpy(ds,&packbuf[1],packbufleng-1);
            ds[packbufleng-1] = 0;
            adduserquote(ds);
            break;
        }

        case PACKET_TYPE_RTS:
        {
            PACKET_RTSp p;

            p = (PACKET_RTSp)packbuf;

            PlaySoundRTS(p->RTSnum);

            break;
        }

        case PACKET_TYPE_NEW_GAME:
        {
            extern SWBOOL NewGame, ShortGameMode, DemoInitOnce;
            PACKET_NEW_GAMEp p;
            extern short TimeLimitTable[];

            pp = Player + otherconnectindex;

            // Dukes New Game Packet
            //level_number //volume_number //player_skill //monsters_off //respawn_monsters
            //respawn_items //respawn_inventory //coop //marker //friendlyfire //boardname

            p = (PACKET_NEW_GAMEp)packbuf;

            ready2send = 0;

            Level = p->Level;
            Skill = p->Skill;

            gNet.HurtTeammate = p->HurtTeammate;
            gNet.SpawnMarkers = p->SpawnMarkers;
            gNet.TeamPlay   = p->TeamPlay;
            gNet.AutoAim    = p->AutoAim;
            gNet.Nuke       = p->Nuke;
            gNet.KillLimit          = p->KillLimit*10;
            gNet.TimeLimit          = TimeLimitTable[p->TimeLimit]*60*120;

            if (ShortGameMode)
            {
                gNet.KillLimit /= 10;
                gNet.TimeLimit /= 2;
            }

            gNet.TimeLimitClock = gNet.TimeLimit;
            gNet.MultiGameType = p->GameType+1;

            // settings for No Respawn Commbat mode
            if (gNet.MultiGameType == MULTI_GAME_COMMBAT_NO_RESPAWN)
            {
                gNet.MultiGameType = MULTI_GAME_COMMBAT;
                gNet.NoRespawn = TRUE;
            }
            else
            {
                gNet.NoRespawn = FALSE;
            }

            ExitLevel = TRUE;
            NewGame = TRUE;
            // restart demo for multi-play mode
            DemoInitOnce = FALSE;
            ResetMenuInput();

            // send a dummy packet to see when it arrives
            //tempbuf[0] = PACKET_TYPE_DUMMY;
            //sendpacket(otherconnectindex, tempbuf, 1);

            ////DSPRINTF(ds,"Level %d, Skill %d, AutoAim %d",Level, Skill, gs.AutoAim);
            //MONO_PRINT(ds);

            break;
        }

        case PACKET_TYPE_DUMMY:
            ////DSPRINTF(ds,"Got Dummy Packet!!!");
            //MONO_PRINT(ds);
            break;

        case PACKET_TYPE_VERSION:
        {
            PACKET_VERSIONp p;

            pp = Player + otherconnectindex;
            p = (PACKET_VERSIONp)packbuf;

            //tenDbLprintf(gTenLog, 3, "rcv pid %d version %lx", (int) otherconnectindex, (int) p->Version);
            pp->PlayerVersion = p->Version;
            break;
        }

        case PACKET_TYPE_PLAYER_OPTIONS:
        {
            PACKET_OPTIONSp p;

            pp = Player + otherconnectindex;
            p = (PACKET_OPTIONSp)packbuf;

            // auto run
            if (p->AutoRun)
                SET(pp->Flags, PF_LOCK_RUN);
            else
                RESET(pp->Flags, PF_LOCK_RUN);

            // palette
            pp->TeamColor = p->Color;
            pp->SpriteP->pal = PALETTE_PLAYER0 + pp->TeamColor;
            User[pp->SpriteP - sprite]->spal = pp->SpriteP->pal;

            // names
            strcpy(pp->PlayerName, p->PlayerName);

            break;
        }

        case PACKET_TYPE_NAME_CHANGE:
        {
            PACKET_NAME_CHANGEp p;
            pp = Player + otherconnectindex;
            p = (PACKET_NAME_CHANGEp)packbuf;

            // someone else has changed their name

            DSPRINTF(ds,"Recieved name: %s",p->PlayerName);
            MONO_PRINT(ds);

            strcpy(pp->PlayerName, p->PlayerName);
            //strcpy(CommPlayerName, p->PlayerName);
            SetRedrawScreen(Player+myconnectindex);
            break;
        }

        case PACKET_TYPE_MENU_LEVEL_QUIT:
        {
            PlayerQuitMenuLevel = otherconnectindex;
            break;
        }

        case PACKET_TYPE_PLAYER_READY:
            Player[otherconnectindex].playerreadyflag++;
            // It's important to return from getpackets() when a ready packet comes in and
            // you are inside waitforeverybody(). Otherwise multiple ready packets can come
            // in inside one waitforeverybody() which causes havoc if that w4e is protecting
            // an initialization step which (heh) for example resets the playerreadyflag count.
            return;
        //break;

        case PACKET_TYPE_DONT_USE:
            break;

        case PACKET_TYPE_NULL_PACKET:
            break;

        case PACKET_TYPE_PROXY:
            buildputs("getpackets(): nested proxy packets!?\n");
            break;

        default:
            DSPRINTF(ds,"Packet type unknown %d",packbuf[0]);
            MONO_PRINT(ds);
        }
    }
}

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

#define PACKET_TYPE_MASTER_TO_SLAVE                 0
#define PACKET_TYPE_SLAVE_TO_MASTER                 1
//#define PACKET_TYPE_PLAYER_NAME                     3
#define PACKET_TYPE_MESSAGE                         4
//#define PACKET_TYPE_GAME_INFO                       8
#define PACKET_TYPE_BROADCAST                       17
#define SERVER_GENERATED_BROADCAST                  18
#define PACKET_TYPE_PROXY                           19

#define PACKET_TYPE_NEW_GAME                        30
//#define PACKET_TYPE_NEW_LEVEL                       31
#define PACKET_TYPE_PLAYER_OPTIONS                  32
#define PACKET_TYPE_RTS                             33
#define PACKET_TYPE_DUMMY                           34
#define PACKET_TYPE_MENU_LEVEL_QUIT                 35
#define PACKET_TYPE_NAME_CHANGE                     36
#define PACKET_TYPE_VERSION                         38

#define PACKET_TYPE_NULL_PACKET                     127
#define PACKET_TYPE_PLAYER_READY                    250
#define PACKET_TYPE_DONT_USE                        255  // old logoff

#define BIT_CODEC TRUE
#define SYNC_TEST TRUE
#define MAXSYNCBYTES 16

#pragma pack(push,1)
// Slave->Master: PlayerIndex = who to send the packet to (-1 = all)
// Master->Slave: PlayerIndex = who sent the packet originally
typedef struct
{
    uint8_t PacketType;  // first byte is always packet type
    uint8_t PlayerIndex;
} PACKET_PROXY,*PACKET_PROXYp;

typedef struct
{
    uint8_t PacketType;  // first byte is always packet type
    uint8_t FirstPlayerIndex;
    SWBOOL AutoAim;
    uint8_t Level;
    uint8_t Episode;
    int8_t Skill;
    uint8_t GameType;
    SWBOOL HurtTeammate;
    SWBOOL SpawnMarkers;
    SWBOOL TeamPlay;
    uint8_t KillLimit;
    uint8_t TimeLimit;
    SWBOOL Nuke;
} PACKET_NEW_GAME,*PACKET_NEW_GAMEp;

typedef struct
{
    uint8_t PacketType;  // first byte is always packet type
    SWBOOL AutoRun;
    uint8_t Color;
    char PlayerName[32];
} PACKET_OPTIONS,*PACKET_OPTIONSp;

typedef struct
{
    uint8_t PacketType;  // first byte is always packet type
    char PlayerName[32];
} PACKET_NAME_CHANGE,*PACKET_NAME_CHANGEp;

typedef struct
{
    uint8_t PacketType;  // first byte is always packet type
    uint8_t RTSnum;
} PACKET_RTS,*PACKET_RTSp;

typedef struct
{
    uint8_t PacketType;  // first byte is always packet type
    int Version;
} PACKET_VERSION,*PACKET_VERSIONp;
#pragma pack(pop)

extern uint8_t syncstat[MAXSYNCBYTES];
extern SWBOOL PredictionOn;
extern PLAYER PredictPlayer;
extern PLAYERp ppp;
extern short predictangpos[MOVEFIFOSIZ];
extern int predictmovefifoplc;
extern SWBOOL Prediction;
extern short NumSyncBytes;

void InitPrediction(PLAYERp pp);
void DoPrediction(PLAYERp ppp);
void CorrectPrediction(int actualfifoplc);

//TENSW: safe packet senders
void netsendpacket(int ind, uint8_t* buf, int len);
void netbroadcastpacket(uint8_t* buf, int len);
int netgetpacket(int *ind, uint8_t* buf);

enum MultiGameTypes
{
    MULTI_GAME_NONE,
    MULTI_GAME_COMMBAT,
    MULTI_GAME_COMMBAT_NO_RESPAWN, // JUST a place holder for menus. DO NOT USE!!!
    MULTI_GAME_COOPERATIVE,
    MULTI_GAME_AI_BOTS
};

//extern int16_t MultiGameType;    // defaults to NONE

// global net vars
// not saved in .CFG file
// used for current game
typedef struct
{
    int32_t KillLimit;
    int32_t TimeLimit;
    int32_t TimeLimitClock;
    int16_t MultiGameType; // used to be a stand alone global
    SWBOOL TeamPlay;
    SWBOOL HurtTeammate;
    SWBOOL SpawnMarkers;
    SWBOOL AutoAim;
    SWBOOL NoRespawn; // for commbat type games
    SWBOOL Nuke;
} gNET,*gNETp;

extern gNET gNet;

typedef struct
{
    int Rules,
        Level,
        Enemy,
        Markers,
        Team,
        HurtTeam,
        Kill,
        Time,
        Color,
        Nuke;
} AUTO_NET, *AUTO_NETp;

extern AUTO_NET Auto;
extern SWBOOL AutoNet;

void UpdateInputs(void);
void getpackets(void);
void SendMulitNameChange(char *new_name);
void InitNetVars(void);
void InitTimingVars(void);
void PauseAction(void);
void ResumeAction(void);
void ErrorCorrectionQuit(void);
void Connect(void);
void waitforeverybody(void);
SWBOOL MenuCommPlayerQuit(short quit_player);
void SendVersion(int version);
void InitNetPlayerOptions(void);
void CheckVersion(int GameVersion);
void SW_SendMessage(short pnum,const char *text);
void PauseGame(void);
void ResumeGame(void);