code:
//-------------------------------------------------------------------------
/*
Copyright (C) 2010 EDuke32 developers and contributors

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

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

#ifndef global_h_
#define global_h_

#include "build.h"
#include "compat.h"
#include "duke3d.h"
#include "mmulti.h"
#include "quotes.h"
#include "sector.h"
#include "sounds.h"

#ifdef global_c_
    #define G_EXTERN
#else
    #define G_EXTERN extern
#endif

#define MAXINTERPOLATIONS MAXSPRITES
#define MAXSKILLS 7

// duke3d global soup :(

G_EXTERN int32_t g_interpolationCnt;
G_EXTERN int32_t g_interpolationLock;
G_EXTERN int32_t oldipos[MAXINTERPOLATIONS];
G_EXTERN int32_t *curipos[MAXINTERPOLATIONS];
G_EXTERN int32_t bakipos[MAXINTERPOLATIONS];

#ifdef __cplusplus
extern "C" {
#endif

G_EXTERN int32_t duke3d_globalflags;

// KEEPINSYNC astub.c (used values only)
enum DUKE3D_GLOBALFLAGS {
    DUKE3D_NO_WIDESCREEN_PINNING = 1<<0,
    DUKE3D_NO_HARDCODED_FOGPALS = 1<<1,
    DUKE3D_NO_PALETTE_CHANGES = 1<<2,
    DUKE3D_GLOBAL_ADDITIVE_HITRADIUS = 1<<3,
};

G_EXTERN DukeStatus_t sbar;
G_EXTERN actor_t actor[MAXSPRITES];
#ifdef POLYMER
G_EXTERN practor_t practor[MAXSPRITES];
#endif
// g_tile: tile-specific data THAT DOES NOT CHANGE during the course of a game
G_EXTERN char *g_tileLabels[MAXTILES];
G_EXTERN tiledata_t g_tile[MAXTILES];
G_EXTERN animwalltype animwall[MAXANIMWALLS];
G_EXTERN char *apStrings[MAXQUOTES],*apXStrings[MAXQUOTES];
G_EXTERN char *label;
G_EXTERN int32_t g_musicIndex;
G_EXTERN char g_loadFromGroupOnly;
G_EXTERN int8_t g_maxDefinedSkill;
G_EXTERN char pus,pub;
G_EXTERN char ready2send;
#define MAXPLAYERNAME 32
G_EXTERN char szPlayerName[MAXPLAYERNAME];
G_EXTERN char tempbuf[MAXSECTORS<<1],packbuf[PACKBUF_SIZE],buf[1024];
#define TYPEBUFSIZE 141
G_EXTERN char typebuf[TYPEBUFSIZE];

G_EXTERN input_t localInput;
G_EXTERN input_t recsync[RECSYNCBUFSIZ];

G_EXTERN int32_t g_activeVscrSprite[MAX_ACTIVE_VIEWSCREENS];
G_EXTERN int32_t g_activeVscrTile[MAX_ACTIVE_VIEWSCREENS];
G_EXTERN int32_t g_animWallCnt;
G_EXTERN int32_t g_animateCnt;
G_EXTERN int32_t g_cloudCnt;
G_EXTERN int32_t g_curViewscreen; // unused, kept for savegame purposes
G_EXTERN int32_t g_frameRate;
G_EXTERN int32_t g_cyclerCnt;
G_EXTERN int32_t g_damageCameras;
G_EXTERN int32_t g_doQuickSave;
G_EXTERN int32_t g_earthquakeTime;
G_EXTERN int32_t g_freezerSelfDamage;
G_EXTERN int32_t g_gameQuit;
G_EXTERN int32_t g_globalRandom;
G_EXTERN int32_t g_impactDamage;
G_EXTERN int32_t g_labelCnt;
G_EXTERN int32_t g_maxPlayerHealth;
G_EXTERN int32_t g_mirrorCount;
G_EXTERN int32_t g_mostConcurrentPlayers;
G_EXTERN int32_t g_musicSize;
G_EXTERN int32_t g_playerSpawnCnt;
G_EXTERN int32_t g_scriptDebug;
G_EXTERN int32_t g_showShareware;
G_EXTERN int32_t g_spriteDeleteQueuePos;
G_EXTERN int32_t g_startArmorAmount;
G_EXTERN int32_t g_tripbombLaserMode;
G_EXTERN int32_t screenpeek;

G_EXTERN int16_t g_animateSect[MAXANIMATES];
G_EXTERN int32_t *g_animatePtr[MAXANIMATES];
G_EXTERN int32_t g_animateGoal[MAXANIMATES];
G_EXTERN int32_t g_animateVel[MAXANIMATES];

G_EXTERN int16_t g_cloudSect[256];
G_EXTERN int16_t g_cloudX;
G_EXTERN int16_t g_cloudY;
G_EXTERN ClockTicks g_cloudClock;

G_EXTERN int16_t SpriteDeletionQueue[1024];
G_EXTERN int16_t g_cyclers[MAXCYCLERS][6];
G_EXTERN int16_t g_mirrorSector[64];
G_EXTERN int16_t g_mirrorWall[64];
G_EXTERN int32_t *labelcode;
G_EXTERN uint8_t *labeltype;
G_EXTERN ClockTicks lockclock;
G_EXTERN ClockTicks ototalclock;

G_EXTERN intptr_t *apScript;
G_EXTERN intptr_t *g_scriptPtr;

G_EXTERN map_t g_mapInfo[(MAXVOLUMES + 1) * MAXLEVELS];  // +1 volume for "intro", "briefing" and "loading" music
G_EXTERN vec2_t g_origins[MAXANIMPOINTS];

// XXX: I think this pragma pack is meaningless here.
// MSDN (https://msdn.microsoft.com/en-us/library/2e70t5y1%28VS.80%29.aspx) says:
// "pack takes effect at the first struct, union, or class declaration after
//  the pragma is seen; pack has no effect on definitions."
#pragma pack(push,1)
#ifdef global_c_
static playerdata_t g_player_s[1 + MAXPLAYERS];
playerdata_t *const g_player = &g_player_s[1];
#else
extern playerdata_t *const g_player;
#endif
G_EXTERN playerspawn_t g_playerSpawnPoints[MAXPLAYERS];
G_EXTERN input_t inputfifo[MOVEFIFOSIZ][MAXPLAYERS];
#pragma pack(pop)

G_EXTERN int32_t g_noEnemies;
G_EXTERN int32_t g_restorePalette;
G_EXTERN int32_t g_screenCapture;
G_EXTERN projectile_t SpriteProjectile[MAXSPRITES];
G_EXTERN uint32_t everyothertime;
G_EXTERN uint32_t g_moveThingsCount;
G_EXTERN double g_gameUpdateTime;
G_EXTERN double g_gameUpdateAndDrawTime;
#define GAMEUPDATEAVGTIMENUMSAMPLES 100
G_EXTERN double g_gameUpdateAvgTime;
G_EXTERN mco_coro *co_drawframe;
G_EXTERN bool     g_frameJustDrawn;
G_EXTERN uint64_t g_lastFrameStartTime, g_lastFrameEndTime, g_lastFrameDuration;
G_EXTERN uint64_t g_lastFrameEndTime2, g_lastFrameDuration2;
G_EXTERN uint32_t g_frameCounter;
G_EXTERN int g_restartFrameRoutine;

#ifndef global_c_
extern int32_t g_frameStackSize;

extern char CheatKeys[2];
extern char g_gametypeNames[MAXGAMETYPES][33];
extern char g_setupFileName[BMAX_PATH];
extern char g_skillNames[MAXSKILLS][33];
extern char g_volumeNames[MAXVOLUMES][33];

extern int32_t g_actorRespawnTime;
extern int32_t g_bouncemineRadius;
extern int32_t g_deleteQueueSize;
extern int32_t g_gametypeCnt;
extern int32_t g_itemRespawnTime;
extern int32_t g_morterRadius;
extern int32_t g_numFreezeBounces;
extern int32_t g_pipebombRadius;
extern int32_t g_playerFriction;
extern int32_t g_rpgRadius;
extern int32_t g_scriptSize;
extern int32_t g_seenineRadius;
extern int32_t g_shrinkerRadius;
extern int32_t g_spriteGravity;
extern int32_t g_timerTicsPerSecond;
extern int32_t g_tripbombRadius;
extern int32_t g_volumeCnt;

extern int16_t g_blimpSpawnItems[15];
extern int32_t g_gametypeFlags[MAXGAMETYPES];
extern int32_t g_volumeFlags[MAXVOLUMES];

extern const char *s_buildDate;

extern const char* g_internalFuncNameTokens[];
#endif

enum
{
    EF_HIDEFROMSP = 1<<0,
    // EF_HIDEFROMMP = 1<<1,
};

EXTERN_INLINE_HEADER void G_UpdateInterpolations(void);
EXTERN_INLINE_HEADER void G_RestoreInterpolations(void);

#ifdef __cplusplus
}
#endif

#if defined global_c_ || !defined DISABLE_INLINING

EXTERN_INLINE void G_UpdateInterpolations(void)  //Stick at beginning of G_DoMoveThings
{
    for (bssize_t i=g_interpolationCnt-1; i>=0; i--) oldipos[i] = *curipos[i];
}

EXTERN_INLINE void G_RestoreInterpolations(void)  //Stick at end of drawscreen
{
    int32_t i=g_interpolationCnt-1;

    if (--g_interpolationLock)
        return;

    for (; i>=0; i--) *curipos[i] = bakipos[i];
}

#endif

#endif


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 2010 EDuke32 developers and contributors

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

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

#include "baselayer.h"
#include "cache1d.h"
#include "common_game.h"
#include "compat.h"
#include "crc32.h"
#include "duke3d.h"
#include "grpscan.h"
#include "scriptfile.h"

#include "vfs.h"

#ifndef EDUKE32_STANDALONE
static void process_vaca13(int32_t crcval);
static void process_vacapp15(int32_t crcval);

// custom GRP support for the startup window, file format reflects the structure below
#define GAMELISTFILE "games.list"
//    name                                     crc          size      flags                         dependency  scriptname     postprocessing
static internalgrpinfo_t const internalgrpfiles[] =
{
    { "Duke Nukem 3D",                         DUKE13_CRC,  26524524, GAMEFLAG_DUKE,                         0, NULL, NULL},
    { "Duke Nukem 3D (South Korean Censored)", DUKEKR_CRC,  26385383, GAMEFLAG_DUKE,                         0, NULL, NULL},
    { "Duke Nukem 3D: Atomic Edition",         DUKE15_CRC,  44356548, GAMEFLAG_DUKE,                         0, NULL, NULL},
    { "Duke Nukem 3D: Atomic Edition (WT)",    DUKEWT_CRC,  44356548, GAMEFLAG_DUKE,                         0, NULL, NULL},
    { "Duke Nukem 3D: Plutonium Pak",          DUKEPP_CRC,  44348015, GAMEFLAG_DUKE,                         0, NULL, NULL},
    { "Duke Nukem 3D Shareware 0.99",          DUKE099_CRC, 9690241,  GAMEFLAG_DUKE|GAMEFLAG_DUKEBETA,       0, NULL, NULL},
    { "Duke Nukem 3D Shareware 1.0",           DUKE10_CRC,  10429258, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL},
    { "Duke Nukem 3D Shareware 1.1",           DUKE11_CRC,  10442980, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL},
    { "Duke Nukem 3D Shareware 1.3D",          DUKESW_CRC,  11035779, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL},
    { "Duke Nukem 3D Mac Demo",                DUKEMD_CRC,  10444391, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL},
    { "Duke Nukem 3D MacUser Demo",            DUKEMD2_CRC, 10628573, GAMEFLAG_DUKE|GAMEFLAG_SHAREWARE,      0, NULL, NULL },
    { "Duke it out in D.C. (1.3D)",            DUKEDC13_CRC, 7926624, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE13_CRC, NULL, NULL},
    { "Duke it out in D.C.",                   DUKEDCPP_CRC, 8225517, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL},
    { "Duke it out in D.C.",                   DUKEDC_CRC,  8410183,  GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL},
    { "Duke it out in D.C.",                   (int32_t) 0x39A692BF,  8410187, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "DUKEDC.CON", NULL},
    { "Duke Caribbean: Life's a Beach (1.3D)", VACA13_CRC,  23559381, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE13_CRC, NULL, process_vaca13},
    { "Duke Caribbean: Life's a Beach (PPak)", VACAPP_CRC,  22551333, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKEPP_CRC, NULL, process_vacapp15},
    { "Duke Caribbean: Life's a Beach",        VACA15_CRC,  22521880, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, process_vacapp15},
    { "Duke Caribbean: Life's a Beach",        DUKECB_CRC,  22213819, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, NULL, NULL},
    { "Duke Caribbean: Life's a Beach",        (int32_t) 0x65B5F690, 22397273, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "VACATION.CON", NULL},
    { "Duke: Nuclear Winter",                  DUKENW_CRC,  16169365, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "NWINTER.CON", NULL},
    { "Duke: Nuclear Winter Demo",             (int32_t) 0xC7EFBFA9,  10965909, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "NWINTER.CON", NULL},
    { "Duke!ZONE II (1.3D)",                   DZ2_13_CRC,  26135388, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE13_CRC, "DZ-GAME.CON", NULL},
    { "Duke!ZONE II",                          DZ2_PP_CRC,  44100411, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "DZ-GAME.CON", NULL},
    { "Duke!ZONE II",                          (int32_t) 0x1E9516F1,  3186656, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "DZ-GAME.CON", NULL},
    { "Duke Nukem's Penthouse Paradise",       (int32_t) 0x7CD82A3B,  2112419, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "ppakgame.con", NULL}, // original .zip release
    { "Duke Nukem's Penthouse Paradise",       (int32_t) 0xCF928A58,  4247491, GAMEFLAG_DUKE|GAMEFLAG_ADDON, DUKE15_CRC, "PPAKGAME.CON", NULL}, // ZOOM Platform repacked .grp
    { "NAM",                                   NAM_CRC,     43448927, GAMEFLAG_NAM,                          0, NULL, NULL},
    { "NAPALM",                                NAPALM_CRC,  44365728, GAMEFLAG_NAM|GAMEFLAG_NAPALM,          0, NULL, NULL},
    { "WWII GI",                               WW2GI_CRC,   77939508, GAMEFLAG_WW2GI,                        0, NULL, NULL},
    { "Platoon Leader",                        PLATOONL_CRC, 37852572, GAMEFLAG_WW2GI|GAMEFLAG_ADDON,        WW2GI_CRC, "PLATOONL.DEF", NULL},
};
#endif

struct grpfile_t *foundgrps = NULL;
struct grpinfo_t *listgrps = NULL;

static void LoadList(const char * filename)
{
    scriptfile *script = scriptfile_fromfile(filename);

    if (!script)
        return;

#ifndef EDUKE32_STANDALONE
    scriptfile_addsymbolvalue("GAMEFLAG_DUKE", GAMEFLAG_DUKE);
    scriptfile_addsymbolvalue("GAMEFLAG_ADDON", GAMEFLAG_DUKE|GAMEFLAG_ADDON);
    scriptfile_addsymbolvalue("GAMEFLAG_NAM", GAMEFLAG_NAM);
    scriptfile_addsymbolvalue("GAMEFLAG_NAPALM", GAMEFLAG_NAM|GAMEFLAG_NAPALM);
    scriptfile_addsymbolvalue("GAMEFLAG_WW2GI", GAMEFLAG_NAM|GAMEFLAG_WW2GI);
    scriptfile_addsymbolvalue("DUKEWT_CRC", DUKEWT_CRC);
    scriptfile_addsymbolvalue("DUKE15_CRC", DUKE15_CRC);
    scriptfile_addsymbolvalue("DUKEPP_CRC", DUKEPP_CRC);
    scriptfile_addsymbolvalue("DUKE13_CRC", DUKE13_CRC);
    scriptfile_addsymbolvalue("DUKEDC13_CRC", DUKEDC13_CRC);
    scriptfile_addsymbolvalue("DUKEDCPP_CRC", DUKEDCPP_CRC);
    scriptfile_addsymbolvalue("DUKEDC_CRC", DUKEDC_CRC);
    scriptfile_addsymbolvalue("VACA13_CRC", VACA13_CRC);
    scriptfile_addsymbolvalue("VACAPP_CRC", VACAPP_CRC);
    scriptfile_addsymbolvalue("VACA15_CRC", VACA15_CRC);
    scriptfile_addsymbolvalue("DUKECB_CRC", DUKECB_CRC);
    scriptfile_addsymbolvalue("DUKENW_CRC", DUKENW_CRC);
    scriptfile_addsymbolvalue("DZ2_13_CRC", DZ2_13_CRC);
    scriptfile_addsymbolvalue("DZ2_PP_CRC", DZ2_PP_CRC);
    scriptfile_addsymbolvalue("NAM_CRC", NAM_CRC);
    scriptfile_addsymbolvalue("NAPALM_CRC", NAPALM_CRC);
    scriptfile_addsymbolvalue("WW2GI_CRC", WW2GI_CRC);
#endif

    while (!scriptfile_eof(script))
    {
        enum
        {
            T_GRPINFO,
            T_GAMENAME,
            T_CRC,
            T_SIZE,
            T_DEPCRC,
            T_SCRIPTNAME,
            T_DEFNAME,
            T_FLAGS,
            T_RTSNAME,
        };

        static const tokenlist profiletokens[] =
        {
            { "grpinfo",            T_GRPINFO },
        };

        int32_t token = getatoken(script,profiletokens,ARRAY_SIZE(profiletokens));
        switch (token)
        {
        case T_GRPINFO:
        {
            int32_t gsize = 0, gcrcval = 0, gflags = GAMEFLAG_DUKE, gdepcrc = DUKE15_CRC;
            char *gname = NULL, *gscript = NULL, *gdef = NULL;
            char *grts = NULL;
            char *grpend = NULL;

            static const tokenlist grpinfotokens[] =
            {
                { "name",           T_GAMENAME },
                { "scriptname",     T_SCRIPTNAME },
                { "defname",        T_DEFNAME },
                { "rtsname",        T_RTSNAME },
                { "crc",            T_CRC },
                { "dependency",     T_DEPCRC },
                { "size",           T_SIZE },
                { "flags",          T_FLAGS },

            };

            if (scriptfile_getbraces(script,&grpend)) break;

            while (script->textptr < grpend)
            {
                int32_t token = getatoken(script,grpinfotokens,ARRAY_SIZE(grpinfotokens));

                switch (token)
                {
                case T_GAMENAME:
                    scriptfile_getstring(script,&gname); break;
                case T_SCRIPTNAME:
                    scriptfile_getstring(script,&gscript); break;
                case T_DEFNAME:
                    scriptfile_getstring(script,&gdef); break;
                case T_RTSNAME:
                    scriptfile_getstring(script,&grts); break;

                case T_FLAGS:
                    scriptfile_getsymbol(script,&gflags); gflags &= GAMEFLAGMASK; break;
                case T_DEPCRC:
                    scriptfile_getsymbol(script,&gdepcrc); break;
                case T_CRC:
                    scriptfile_getsymbol(script,&gcrcval); break;
                case T_SIZE:
                    scriptfile_getnumber(script,&gsize); break;
                default:
                    break;
                }

                grpinfo_t * const fg = (grpinfo_t *)Xcalloc(1, sizeof(grpinfo_t));
                fg->next = listgrps;
                listgrps = fg;

                if (gname)
                    fg->name = Xstrdup(gname);

                fg->size = gsize;
                fg->crcval = gcrcval;
                fg->dependency = gdepcrc;
                fg->game = gflags;

                if (gscript)
                    fg->scriptname = dup_filename(gscript);

                if (gdef)
                    fg->defname = dup_filename(gdef);

                if (grts)
                    fg->rtsname = dup_filename(grts);
            }
            break;
        }

        default:
            break;
        }
    }

    scriptfile_close(script);
    scriptfile_clearsymbols();
}

static void LoadGameList(void)
{
#ifndef EDUKE32_STANDALONE
    for (size_t i = 0; i < ARRAY_SIZE(internalgrpfiles); i++)
    {
        grpinfo_t * const fg = (grpinfo_t *)Xcalloc(1, sizeof(grpinfo_t));

        fg->name = Xstrdup(internalgrpfiles[i].name);
        fg->crcval = internalgrpfiles[i].crcval;
        fg->size = internalgrpfiles[i].size;
        fg->game = internalgrpfiles[i].game;
        fg->dependency = internalgrpfiles[i].dependency;

        if (internalgrpfiles[i].scriptname)
            fg->scriptname = dup_filename(internalgrpfiles[i].scriptname);

        fg->postprocessing = internalgrpfiles[i].postprocessing;

        fg->next = listgrps;
        listgrps = fg;
    }
#endif

#ifdef USE_PHYSFS
    auto const base = PHYSFS_getBaseDir();
#else
    static char const base[] = "/";
#endif
    BUILDVFS_FIND_REC * const srch = klistpath(base, "*.grpinfo", BUILDVFS_FIND_FILE);

    for (BUILDVFS_FIND_REC *sidx = srch; sidx; sidx = sidx->next)
        LoadList(sidx->name);

    klistfree(srch);
}

static void FreeGameList(void)
{
    while (listgrps)
    {
        Xfree(listgrps->name);
        Xfree(listgrps->scriptname);
        Xfree(listgrps->defname);
        Xfree(listgrps->rtsname);

        grpinfo_t * const fg = listgrps->next;
        Xfree(listgrps);
        listgrps = fg;
    }
}

#define GRPCACHEFILE "grpfiles.cache"
static struct grpcache
{
    struct grpcache *next;
    int32_t size;
    int32_t mtime;
    int32_t crcval;
    char name[BMAX_PATH];
}
*grpcache = NULL, *usedgrpcache = NULL;

static int32_t LoadGroupsCache(void)
{
    struct grpcache *fg;

    int32_t fsize, fmtime, fcrcval;
    char *fname;

    scriptfile *script;

    script = scriptfile_fromfile(GRPCACHEFILE);
    if (!script) return -1;

    while (!scriptfile_eof(script))
    {
        if (scriptfile_getstring(script, &fname)) break;    // filename
        if (scriptfile_getnumber(script, &fsize)) break;    // filesize
        if (scriptfile_getnumber(script, &fmtime)) break;   // modification time
        if (scriptfile_getnumber(script, &fcrcval)) break;  // crc checksum

        fg = (struct grpcache *)Xcalloc(1, sizeof(struct grpcache));
        fg->next = grpcache;
        grpcache = fg;

        Bstrncpyz(fg->name, fname, BMAX_PATH);
        fg->size = fsize;
        fg->mtime = fmtime;
        fg->crcval = fcrcval;
    }

    scriptfile_close(script);
    return 0;
}

static void FreeGroupsCache(void)
{
    while (grpcache)
    {
        struct grpcache * const fg = grpcache->next;
        Xfree(grpcache);
        grpcache = fg;
    }
}

static void RemoveGroup(grpfile_t *igrp)
{
    for (grpfile_t *prev = NULL, *grp = foundgrps; grp; grp=grp->next)
    {
        if (grp == igrp)
        {
            if (grp == foundgrps)
                foundgrps = grp->next;
            else
                prev->next = grp->next;

            Xfree((char *)grp->filename);
            Xfree(grp);

            return;
        }

        prev = grp;
    }
}

grpfile_t * FindGroup(int32_t crcval)
{
    grpfile_t *grp;

    for (grp = foundgrps; grp; grp=grp->next)
    {
        if (grp->type->crcval == crcval)
            return grp;
    }

    return NULL;
}

#ifndef USE_PHYSFS
static grpinfo_t const * FindGrpInfo(int32_t crcval, int32_t size)
{
    grpinfo_t *grpinfo;

    for (grpinfo = listgrps; grpinfo; grpinfo=grpinfo->next)
    {
        if (grpinfo->crcval == crcval && grpinfo->size == size)
            return grpinfo;
    }

    return NULL;
}

static void ProcessGroups(BUILDVFS_FIND_REC *srch, native_t maxsize)
{
    BUILDVFS_FIND_REC *sidx;
    struct grpcache *fg, *fgg;
    char *fn;
    struct Bstat st;

    static constexpr int ReadSize = 65536;

    auto buf = (uint8_t *)Xmalloc(ReadSize);

    for (sidx = srch; sidx; sidx = sidx->next)
    {
        for (fg = grpcache; fg; fg = fg->next)
        {
            if (!Bstrcmp(fg->name, sidx->name)) break;
        }

        if (fg)
        {
            if (findfrompath(sidx->name, &fn)) continue; // failed to resolve the filename
            if (Bstat(fn, &st))
            {
                Xfree(fn);
                continue;
            } // failed to stat the file
            Xfree(fn);
            if (fg->size == (int32_t)st.st_size && fg->mtime == (int32_t)st.st_mtime)
            {
                grpinfo_t const * const grptype = FindGrpInfo(fg->crcval, fg->size);
                if (grptype)
                {
                    grpfile_t * const grp = (grpfile_t *)Xcalloc(1, sizeof(grpfile_t));
                    grp->filename = Xstrdup(sidx->name);
                    grp->type = grptype;
                    grp->next = foundgrps;
                    foundgrps = grp;
                }

                fgg = (struct grpcache *)Xcalloc(1, sizeof(struct grpcache));
                strcpy(fgg->name, fg->name);
                fgg->size = fg->size;
                fgg->mtime = fg->mtime;
                fgg->crcval = fg->crcval;
                fgg->next = usedgrpcache;
                usedgrpcache = fgg;
                continue;
            }
        }

        {
            int32_t b, fh;
            int32_t crcval = 0;

            fh = openfrompath(sidx->name, BO_RDONLY|BO_BINARY, BS_IREAD);
            if (fh < 0) continue;
            if (Bfstat(fh, &st)) continue;
            if (st.st_size > maxsize) continue;

            DLOG_F(INFO, " Checksumming %s...", sidx->name);
            do
            {
                b = read(fh, buf, ReadSize);
                if (b > 0) crcval = Bcrc32((uint8_t *)buf, b, crcval);
            }
            while (b == ReadSize);
            close(fh);

            LOG_F(INFO, " %s has checksum 0x%08x", sidx->name, crcval);

            grpinfo_t const * const grptype = FindGrpInfo(crcval, st.st_size);
            if (grptype)
            {
                grpfile_t * const grp = (grpfile_t *)Xcalloc(1, sizeof(grpfile_t));
                grp->filename = Xstrdup(sidx->name);
                grp->type = grptype;
                grp->next = foundgrps;
                foundgrps = grp;
            }

            fgg = (struct grpcache *)Xcalloc(1, sizeof(struct grpcache));
            Bstrncpyz(fgg->name, sidx->name, BMAX_PATH);
            fgg->size = st.st_size;
            fgg->mtime = st.st_mtime;
            fgg->crcval = crcval;
            fgg->next = usedgrpcache;
            usedgrpcache = fgg;
        }
    }

    Xfree(buf);
}
#endif

int32_t ScanGroups(void)
{
#ifndef USE_PHYSFS
    struct grpcache *fg, *fgg;

    LOG_F(INFO, "Searching for game data...");

    LoadGameList();
    LoadGroupsCache();

    native_t maxsize = 0;
    for (grpinfo_t * grpinfo = listgrps; grpinfo; grpinfo = grpinfo->next)
    {
        if (maxsize < grpinfo->size)
            maxsize = grpinfo->size;
    }

    static char const *extensions[] =
    {
        "*.grp",
        "*.ssi",
        "*.dat",
        "*.zip",
    };

    for (char const *extension : extensions)
    {
        BUILDVFS_FIND_REC *srch = klistpath("/", extension, BUILDVFS_FIND_FILE);
        ProcessGroups(srch, maxsize);
        klistfree(srch);
    }

    FreeGroupsCache();

    for (grpfile_t *grp = foundgrps; grp; grp=grp->next)
    {
        if (grp->type->dependency)
        {
            if (FindGroup(grp->type->dependency) == NULL) // couldn't find dependency
            {
                //initprintf("removing %s\n", grp->name);
                RemoveGroup(grp);
                grp = foundgrps;
                // start from the beginning so we can remove anything that depended on this grp
                continue;
            }
        }
    }

    if (usedgrpcache)
    {
        int32_t i = 0;
        buildvfs_FILE fp = buildvfs_fopen_write(GRPCACHEFILE);
        if (fp)
        {
            for (fg = usedgrpcache; fg; fg=fgg)
            {
                fgg = fg->next;
                fprintf(fp, "\"%s\" %d %d %d\n", fg->name, fg->size, fg->mtime, fg->crcval);
                Xfree(fg);
                i++;
            }
            buildvfs_fclose(fp);
        }
//        initprintf("Found %d recognized GRP %s.\n",i,i>1?"files":"file");

        return 0;
    }

    LOG_F(ERROR, "Found no recognized game data!");
#endif

    return 0;
}

void FreeGroups(void)
{
    while (foundgrps)
    {
        Xfree((char *)foundgrps->filename);
        grpfile_t * const fg = foundgrps->next;
        Xfree(foundgrps);
        foundgrps = fg;
    }

    FreeGameList();
}

#ifndef EDUKE32_STANDALONE
static void process_vaca13(int32_t crcval)
{
    krename(crcval, 0, "ADDREE.VOC");
    krename(crcval, 1, "BALLBOOM.VOC");
    krename(crcval, 2, "BARMUSIC.VOC");
    krename(crcval, 3, "BCHBALL.VOC");
    krename(crcval, 4, "BOING.VOC");
    krename(crcval, 5, "CHACHA.VOC");
    krename(crcval, 6, "CHAINDRV.VOC");
    krename(crcval, 7, "CHEAP01.VOC");
    krename(crcval, 8, "CHEER.VOC");
    krename(crcval, 9, "CHNSQRT.VOC");
    krename(crcval, 10, "COCOANUT.VOC");
    krename(crcval, 11, "CRUSH2.VOC");
    krename(crcval, 12, "DEFLATE2.VOC");
    krename(crcval, 13, "DRAGHURT.VOC");
    krename(crcval, 14, "DRAGROAM.VOC");
    krename(crcval, 15, "DRAGSHOT.VOC");
    krename(crcval, 16, "DUKE01.VOC");
    krename(crcval, 17, "ELEV1.VOC");
    krename(crcval, 18, "GMEOVR05.VOC");
    krename(crcval, 19, "GULLDIE.VOC");
    krename(crcval, 20, "GULLHURT.VOC");
    krename(crcval, 21, "GULLROAM.VOC");
    krename(crcval, 22, "GULLSHIT.VOC");
    krename(crcval, 23, "HELP04.VOC");
    krename(crcval, 24, "ICECONCH.VOC");
    krename(crcval, 25, "IDLEBOAT.VOC");
    krename(crcval, 26, "KICKHEAD.VOC");
    krename(crcval, 27, "LANI05.VOC");
    krename(crcval, 28, "LANI08.VOC");
    krename(crcval, 29, "LANIDUK2.VOC");
    krename(crcval, 30, "MUSCLE01.VOC");
    krename(crcval, 31, "MUSCLE04.VOC");
    krename(crcval, 32, "MUZAK.VOC");
    krename(crcval, 33, "PINEFALL.VOC");
    krename(crcval, 34, "POINT07.VOC");
    krename(crcval, 35, "POINT08.VOC");
    krename(crcval, 36, "RADIO.VOC");
    krename(crcval, 37, "RUIN01.VOC");
    krename(crcval, 38, "SCREAM.VOC");
    krename(crcval, 39, "SCREAM04.VOC");
    krename(crcval, 40, "SCREAM9.VOC");
    krename(crcval, 41, "SHIPHORN.VOC");
    krename(crcval, 42, "SNGLGULL.VOC");
    krename(crcval, 43, "SQRT4.VOC");
    krename(crcval, 44, "SQUIRT1.VOC");
    krename(crcval, 45, "SSCOOL1.VOC");
    krename(crcval, 46, "SSCOOL2.VOC");
    krename(crcval, 47, "SSCOOL3.VOC");
    krename(crcval, 48, "SSDIE1.VOC");
    krename(crcval, 49, "SSDIE2.VOC");
    krename(crcval, 50, "SSNORM01.VOC");
    krename(crcval, 51, "SSNORM02.VOC");
    krename(crcval, 52, "SSNORM03.VOC");
    krename(crcval, 53, "SSNORM04.VOC");
    krename(crcval, 54, "SSNORM05.VOC");
    krename(crcval, 55, "SSNORM06.VOC");
    krename(crcval, 56, "SSNORM07.VOC");
    krename(crcval, 57, "SSNORM08.VOC");
    krename(crcval, 58, "SSNORM10.VOC");
    krename(crcval, 59, "SSNORM11.VOC");
    krename(crcval, 60, "SSNORM12.VOC");
    krename(crcval, 61, "SSNORM13.VOC");
    krename(crcval, 62, "SSNORM14.VOC");
    krename(crcval, 63, "SSNORM15.VOC");
    krename(crcval, 64, "SSNORM16.VOC");
    krename(crcval, 65, "SSNORM17.VOC");
    krename(crcval, 66, "SSNORM18.VOC");
    krename(crcval, 67, "SSNORM19.VOC");
    krename(crcval, 68, "SSNORM20.VOC");
    krename(crcval, 69, "SSTAUNT1.VOC");
    krename(crcval, 70, "SSTAUNT2.VOC");
    krename(crcval, 71, "SSTAUNT3.VOC");
    krename(crcval, 72, "SSTAUNT4.VOC");
    krename(crcval, 73, "SSTAUNT5.VOC");
    krename(crcval, 74, "SSTAUNT6.VOC");
    krename(crcval, 75, "SSTAUNT7.VOC");
    krename(crcval, 76, "SSTAUNT8.VOC");
    krename(crcval, 77, "SURF.VOC");
    krename(crcval, 78, "TAN01.VOC");
    krename(crcval, 79, "TAN04.VOC");
    krename(crcval, 80, "VINESNAP.VOC");
    krename(crcval, 81, "VOODRUMS.VOC");
    krename(crcval, 82, "WIND54.VOC");
    krename(crcval, 83, "DOOMSDAY.MID");
    krename(crcval, 84, "DUKE-O.MID");
    krename(crcval, 85, "IRIEPRTY.MID");
    krename(crcval, 86, "JUNGVEIN.MID");
    krename(crcval, 87, "PRTYCRUZ.MID");
    krename(crcval, 88, "SOL-MAN1.MID");
    krename(crcval, 90, "CINEOV3.ANM");
    krename(crcval, 91, "DUKETEAM.ANM");
    krename(crcval, 92, "BEACHBAB.CON");
    krename(crcval, 93, "BEACHBAL.CON");
    krename(crcval, 94, "BEACHBTH.CON");
    krename(crcval, 95, "DEFS.CON");
    krename(crcval, 96, "DRAGON.CON");
    krename(crcval, 97, "GAME.CON");
    krename(crcval, 98, "SEAGULL.CON");
    krename(crcval, 99, "SOUNDS.CON");
    krename(crcval, 100, "USER.CON");
    krename(crcval, 101, "DEMO1.DMO");
    krename(crcval, 102, "DEMO2.DMO");
    krename(crcval, 103, "DEMO3.DMO");
    krename(crcval, 104, "VACA1.MAP");
    krename(crcval, 105, "VACA2.MAP");
    krename(crcval, 106, "VACA3.MAP");
    krename(crcval, 107, "VACA4.MAP");
    krename(crcval, 108, "VACA5.MAP");
    krename(crcval, 109, "VACA6.MAP");
    krename(crcval, 110, "VACA7.MAP");
    krename(crcval, 111, "VACADM1.MAP");
    krename(crcval, 112, "VACADM2.MAP");
    krename(crcval, 113, "VACADM3.MAP");
    krename(crcval, 114, "VACADM4.MAP");
    krename(crcval, 115, "VACASL.MAP");
    krename(crcval, 120, "TILES000.ART");
    krename(crcval, 121, "TILES001.ART");
    krename(crcval, 122, "TILES003.ART");
    krename(crcval, 123, "TILES005.ART");
    krename(crcval, 124, "TILES006.ART");
    krename(crcval, 125, "TILES007.ART");
    krename(crcval, 126, "TILES008.ART");
    krename(crcval, 127, "TILES009.ART");
    krename(crcval, 128, "TILES010.ART");
    krename(crcval, 129, "TILES012.ART");
    krename(crcval, 130, "TILES014.ART");
}

static void process_vacapp15(int32_t crcval)
{
    krename(crcval, 5, "DEFS.CON");
    krename(crcval, 6, "GAME.CON");
    krename(crcval, 7, "USER.CON");
    krename(crcval, 8, "DEMO1.DMO");
    krename(crcval, 9, "DEMO2.DMO");
    krename(crcval, 10, "DEMO3.DMO");

    initgroupfile("VACATION.PRG");
}
#endif

repo_name: orochi/nblood

license: mit


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 2010 EDuke32 developers and contributors

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

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

#ifndef grpscan_h_
#define grpscan_h_

#ifdef __cplusplus
extern "C" {
#endif

#define MAXLISTNAMELEN 32

// List of internally-known GRP files
#define DUKE13_CRC  (int32_t)0xBBC9CE44
#define DUKEKR_CRC  (int32_t)0xAA4F6A40
#define DUKE15_CRC  (int32_t)0xFD3DCFF1
#define DUKEPP_CRC  (int32_t)0xF514A6AC
#define DUKEWT_CRC  (int32_t)0x982AFE4A
#define DUKE099_CRC (int32_t)0x02F18900
#define DUKE10_CRC  (int32_t)0xA28AA589
#define DUKE11_CRC  (int32_t)0x912E1E8D
#define DUKESW_CRC  (int32_t)0x983AD923
#define DUKEMD_CRC  (int32_t)0xC5F71561
#define DUKEMD2_CRC  (int32_t)0x73A15EE7
#define DUKEDC13_CRC (int32_t)0xA9242158
#define DUKEDCPP_CRC (int32_t)0xB79D997F
#define DUKEDC_CRC  (int32_t)0xA8CF80DA
#define VACA13_CRC  (int32_t)0x4A2DBB62
#define VACAPP_CRC  (int32_t)0x2F4FCCEE
#define VACA15_CRC  (int32_t)0xB62B42FD
#define DUKECB_CRC  (int32_t)0x18F01C5B
#define DUKENW_CRC  (int32_t)0xF1CAE8E4
#define DZ2_13_CRC  (int32_t)0x82C1B47F
#define DZ2_PP_CRC  (int32_t)0x7FB6117C
#define NAM_CRC     (int32_t)0x75C1F07B
#define NAPALM_CRC  (int32_t)0x3DE1589A
#define WW2GI_CRC   (int32_t)0x907B82BF
#define PLATOONL_CRC (int32_t)0xD1ED8C0C

enum addon_t {
    ADDON_NONE,
    ADDON_DUKEDC,
    ADDON_NWINTER,
    ADDON_CARIBBEAN,
    NUMADDONS
};

typedef struct internalgrpinfo_t {
    char const *name;
    int32_t const crcval;
    int32_t const size;
    int32_t const game;
    int32_t const dependency;
    char const *scriptname;
    void(*postprocessing)(int32_t);
} internalgrpinfo_t;

typedef struct grpinfo_t {
	char *name;
	int32_t crcval;
	int32_t size;
	int32_t game;
    int32_t dependency;
    char *scriptname;
    char *defname;
    char *rtsname;
    void (*postprocessing)(int32_t);
	struct grpinfo_t *next;
} grpinfo_t;

typedef struct grpfile_t {
	char *filename;
	struct grpinfo_t const *type;
	struct grpfile_t *next;
} grpfile_t;

extern grpfile_t *foundgrps;
extern grpinfo_t *listgrps;

extern grpfile_t * FindGroup(int32_t crcval);

int32_t ScanGroups(void);
void FreeGroups(void);

#ifdef __cplusplus
}
#endif

#endif


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 2015 EDuke32 developers and contributors
Copyright (C) 2015 Voidpoint, LLC

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

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

#include "compat.h"
#include "sdl_inc.h"
#include "baselayer.h"
#include "keys.h"
#include "duke3d.h"
#include "common_game.h"
#include "osd.h"
#include "player.h"
#include "game.h"
#include "build.h"
#include "anim.h"
#include "player.h"

#include "keyboard.h"
#include "control.h"
#include "_control.h"

#include "menus.h"

#ifdef __cplusplus
extern "C" {
#endif
extern int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode);
extern int SDL_SendKeyboardText(const char *text);
extern int SDL_SendMouseMotion(SDL_Window * window, Uint32 mouseID, int relative, int x, int y);
extern int SDL_SendMouseButton(SDL_Window * window, Uint32 mouseID, Uint8 state, Uint8 button);

#ifdef __cplusplus
}
#endif

#include "in_android.h"
#include <android/log.h>

#if defined __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"DUKE", __VA_ARGS__))

static char sdl_text[2];

droidinput_t droidinput;

void AndroidTimer(int tics) { G_InitTimer(tics);  }

int AndroidKeyEvent(int state, int code,int unicode)
{
    LOGI("AndroidKeyEvent %d %d %d",state,(SDL_Scancode)code,unicode);
    SDL_SendKeyboardKey(state ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)code);
    SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);

    // if (code == 42)
    //    unicode = 42;

    if (state)
    {
        //if (unicode < 128)
        {
            sdl_text[0] = unicode;
            sdl_text[1] = 0;

            int posted = SDL_SendKeyboardText((const char*)sdl_text);
            LOGI("posted = %d",posted);
        }

        if (state == 2)
            AndroidKeyEvent(0, code, unicode);
    }

    return 0;
}

void AndroidMouseMenu(float x,float y)
{
    SDL_SendMouseMotion(NULL,0,0,x,y);
}

void AndroidMouseMenuButton(int state,int button)
{
    SDL_SendMouseButton(NULL, SDL_TOUCH_MOUSEID, state?SDL_PRESSED:SDL_RELEASED, SDL_BUTTON_LEFT);
}

void changeActionState(int state, int action)
{
    if (state)
    {
        //BUTTONSET(action,1);
        droidinput.functionSticky  |= ((uint64_t)1<<((uint64_t)(action)));
        droidinput.functionHeld    |= ((uint64_t)1<<((uint64_t)(action)));
        return;
    }

    //BUTTONCLEAR(action);
    droidinput.functionHeld  &= ~((uint64_t) 1<<((uint64_t) (action)));
}

void AndroidAction(int state, int action)
{
    LOGI("AndroidAction action = %d, state = %d", action, state);

    if (action >= MENU_UP && action <= MENU_BACK)
    {
        int const sdl_code [] = { SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT,
                SDL_SCANCODE_RIGHT, SDL_SCANCODE_RETURN, SDL_SCANCODE_ESCAPE };
        AndroidKeyEvent(state, sdl_code[action-MENU_UP], 0);
        return;
    }
    else
    {
        //if (AndroidRead(READ_SCREEN_MODE) != TOUCH_SCREEN_GAME) //If not in game don't do any of this
        ///     return;

        //Special toggle for crouch, NOT when using jetpack or in water
        if (droidinput.toggleCrouch)
        {
            int lotag = sector[g_player[myconnectindex].ps->cursectnum].lotag;

            if (droidinput.crouchToggleState && (lotag == ST_2_UNDERWATER || lotag == ST_1_ABOVE_WATER))
            {
                droidinput.crouchToggleState = 0;
                if (action == gamefunc_Crouch)
                    state = 0;
                else AndroidAction(0, gamefunc_Crouch);
            }

            if (action == gamefunc_Crouch)
            {
                if (!g_player[myconnectindex].ps->jetpack_on && g_player[myconnectindex].ps->on_ground &&
                    lotag != ST_2_UNDERWATER && lotag != ST_1_ABOVE_WATER)
                {
                    if (state)
                        droidinput.crouchToggleState = !droidinput.crouchToggleState;

                    state = droidinput.crouchToggleState;
                }
            }

        }

        //Check if jumping while crouched
        if (action == gamefunc_Jump)
        {
            if (droidinput.crouchToggleState)
            {
                droidinput.crouchToggleState = 0;
                changeActionState(0, gamefunc_Crouch);
            }
            else
                changeActionState(state, action);
        }
        else
            changeActionState(state, action);

        if (state == 2)
            AndroidAction(0, action);

        // LOGI("AndroidAction state = 0x%016llX", CONTROL_ButtonState);
    }
}

int const deadRegion = 0.3;

float analogCalibrate(float v)
{
    float rv = 0;

    if (v > deadRegion) rv = (v - deadRegion) * (v - deadRegion);
    else if (-v > deadRegion) rv = -(-v - deadRegion) * (-v - deadRegion);

    return rv;
}

//Need these NAN check as not cumulative.
void AndroidMove(float fwd, float strafe)
{
    if (!ud.auto_run)
    {
        fwd *= 0.5f;
        strafe *= 0.5f;
    }

    if (!isnan(fwd))
        droidinput.forwardmove = fclamp2(analogCalibrate(fwd), -1.f, 1.f);

    if (!isnan(strafe))
        droidinput.sidemove    = fclamp2(analogCalibrate(strafe),    -1.f, 1.f);
}

void AndroidLook(float yaw, float pitch)
{
    droidinput.pitch += pitch;
    droidinput.yaw   += yaw;
}

void AndroidLookJoystick(float yaw, float pitch)
{
    if (!isnan(pitch))
        droidinput.pitch_joystick = analogCalibrate(pitch);

    if (!isnan(yaw))
        droidinput.yaw_joystick   = analogCalibrate(yaw);
}

void AndroidOSD(const char * cmd)
{
    OSD_Dispatch(cmd);
}

int consoleShown = 0;
void AndroidSetConsoleShown(int onf)
{
    consoleShown = onf;
}

extern int inExtraScreens; //In game.c
int32_t AndroidRead(portableread_t r)
{
    int32_t rv;

    switch (r)
    {
    case R_TOUCH_MODE:
        if (g_animPtr || inExtraScreens)
            rv = TOUCH_SCREEN_BLANK_TAP;
        else if (consoleShown)
            rv = TOUCH_SCREEN_CONSOLE;
        else if ((g_player[myconnectindex].ps->gm & MODE_MENU) == MODE_MENU && g_currentMenu != MENU_MAIN)
            rv = (m_currentMenu->type == Verify && totalclock > (m_animation.length + m_animation.start)) ? TOUCH_SCREEN_YES_NO : TOUCH_SCREEN_MENU;
        else if ((g_player[myconnectindex].ps->gm & MODE_MENU) == MODE_MENU && g_currentMenu == MENU_MAIN)
            rv = TOUCH_SCREEN_MENU_NOBACK;
/*
        else if (ud.overhead_on == 2)
            rv = TOUCH_SCREEN_AUTOMAP;
*/
        else if ((g_player[myconnectindex].ps->gm & MODE_GAME))
            if (AndroidRead(R_PLAYER_DEAD_FLAG))
                rv = TOUCH_SCREEN_BLANK_TAP;
            else
                rv = TOUCH_SCREEN_GAME;
        else
            rv = TOUCH_SCREEN_BLANK_TAP;
         break;
    case R_PLAYER_GOTWEAPON:
        rv = g_player[myconnectindex].ps->gotweapon; break;
    case R_UD_OVERHEAD_ON:
        rv = 0; break;//ud.overhead_on != 0;  break;// ud.overhead_on ranges from 0-2
    case R_UD_SCROLLMODE:
        rv = ud.scrollmode; break;
    case R_PLAYER_LASTWEAPON:
        rv = droidinput.lastWeapon;
        if ((unsigned)rv < MAX_WEAPONS && !g_player[myconnectindex].ps->ammo_amount[rv])
            rv = -1;
        break;
    case R_GAME_PAUSED:
        rv = ud.pause_on != 0; break;
    case R_PLAYER_DEAD_FLAG:
        rv = g_player[myconnectindex].ps->dead_flag; break;
    case R_PLAYER_INV_AMOUNT:
        rv = 0;
        for (bssize_t i = 0; i < GET_MAX; i++)
        {
            if (g_player[myconnectindex].ps->inv_amount[i])
                rv += (1 << i);
        }
        break;
    case R_SOMETHINGONPLAYER:
        rv = g_player[myconnectindex].ps->somethingonplayer != -1;
        break;
    default:
        rv = 0; break;
    }

    return rv;
}

static float map_zoom,map_dx,map_dy = 0;

void AndroidAutomapControl(float zoom,float dx,float dy)
{
    map_zoom += zoom;
    map_dx += dx;
    map_dy += dy;
}

///This stuff is called from the game/engine

extern void  CONTROL_Android_ScrollMap(int32_t *angle,int32_t *x, int32_t *y, uint16_t *zoom )
{

    *x += ((int)(map_dx * -30000)*sintable[(512+2048-*angle)&2047])>>14;
    *y += ((int)(map_dy * -30000)*sintable[(512+1024-512-*angle)&2047])>>14;

//    *zoom += map_zoom * 2000;
    //*angle = 0;
    map_dx = map_dy = map_zoom = 0;
}

void CONTROL_Android_SetLastWeapon(int w)
{
    droidinput.lastWeapon = w;
}

void CONTROL_Android_ClearButton(int32_t whichbutton)
{
    droidinput.functionHeld  &= ~((uint64_t)1<<((uint64_t)(whichbutton)));
}

void CONTROL_Android_PollDevices(ControlInfo *info)
{
    //LOGI("CONTROL_Android_PollDevices %f %f",forwardmove,sidemove);
    //LOGI("CONTROL_Android_PollDevices %f %f",droidinput.pitch,droidinput.yaw);

    info->dz = (int32_t)nearbyintf(-droidinput.forwardmove * ANDROIDMOVEFACTOR);
    info->dx = (int32_t)nearbyintf(droidinput.sidemove * ANDROIDMOVEFACTOR) >> 5;
    info->dpitch =
    (int32_t)nearbyintf(droidinput.pitch * ANDROIDLOOKFACTOR + droidinput.pitch_joystick * ANDROIDPITCHFACTORJOYSTICK);
    info->dyaw =
    (int32_t)nearbyintf(-droidinput.yaw * ANDROIDLOOKFACTOR - droidinput.yaw_joystick * ANDROIDYAWFACTORJOYSTICK);

    droidinput.pitch = droidinput.yaw = 0.f;
    CONTROL_ButtonState = droidinput.functionSticky | droidinput.functionHeld;
    droidinput.functionSticky = 0;

    //LOGI("poll state = 0x%016llX",CONTROL_ButtonState);
}

#if defined __GNUC__
# pragma GCC diagnostic pop
#endif


code:
#include "function.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define MENU_UP                  0x200
#define MENU_DOWN                0x201
#define MENU_LEFT                0x202
#define MENU_RIGHT               0x203
#define MENU_SELECT              0x204
#define MENU_BACK                0x205

#define KEY_QUICK_CMD    0x1005
#define KEY_SHOW_KBRD    0x1008
#define KEY_SHOW_INVEN    0x1009
#define KEY_QUICK_SAVE    0x100A
#define KEY_QUICK_LOAD    0x100B

#define KEY_QUICK_KEY1    0x1011
#define KEY_QUICK_KEY2    0x1012
#define KEY_QUICK_KEY3    0x1013
#define KEY_QUICK_KEY4    0x1014

// #define BUTTONSET(x,value) (CONTROL_ButtonState |= ((uint64_t)value<<((uint64_t)(x))))
// #define BUTTONCLEAR(x) (CONTROL_ButtonState &= ~((uint64_t)1<<((uint64_t)(x))))

#define PRECISIONSHOOTFACTOR        0.3f

// where do these numbers come from?
#define ANDROIDMOVEFACTOR           6400
#define ANDROIDLOOKFACTOR          1600

#define ANDROIDPITCHFACTORJOYSTICK          2000
#define ANDROIDYAWFACTORJOYSTICK            4000

typedef enum {
    R_TOUCH_MODE,
    R_PLAYER_GOTWEAPON,
    R_UD_OVERHEAD_ON,
    R_UD_SCROLLMODE,
    R_PLAYER_LASTWEAPON,
    R_GAME_PAUSED,
    R_PLAYER_DEAD_FLAG,
    R_PLAYER_INV_AMOUNT,
    R_SOMETHINGONPLAYER
} portableread_t;

typedef enum {
    TOUCH_SCREEN_BLANK, //Nothing on screen (not used)
    TOUCH_SCREEN_BLANK_TAP, //One button filling screen with no graphic, tap to send Enter key
    TOUCH_SCREEN_YES_NO, //Yes/No buttons on screen, sends Enter or Esc
    TOUCH_SCREEN_MENU, //Normal menu
    TOUCH_SCREEN_MENU_NOBACK, // menu without back button
    TOUCH_SCREEN_GAME, //Normal game screen
    TOUCH_SCREEN_AUTOMAP, //When auto map is up (not used yet)
    TOUCH_SCREEN_CONSOLE //When Console is up
} touchscreemode_t;

typedef struct
{
    int32_t crouchToggleState;
    int32_t lastWeapon;
    int32_t toggleCrouch;
    int32_t quickSelectWeapon;

    uint64_t functionSticky; //To let at least one tick
    uint64_t functionHeld;

    int32_t left_double_action;
    int32_t right_double_action;

    int32_t invertLook, hideStick;

    double pitch, yaw;
    double pitch_joystick, yaw_joystick;
    float forwardmove, sidemove;

    // set by configuration UI
    float strafe_sens, forward_sens;
    float pitch_sens, yaw_sens;

    float gameControlsAlpha;
} droidinput_t;

typedef struct
{
    int32_t audio_sample_rate;
    int32_t audio_buffer_size;
    uint16_t screen_width, screen_height;
} droidsysinfo_t;

extern droidinput_t droidinput;
extern droidsysinfo_t droidinfo;

void AndroidTimer(int tics);
int AndroidKeyEvent(int state, int code, int unicode);
int AndroidRead(portableread_t r);

void AndroidAction(int state, int action);

void AndroidMouseMenu(float x,float y);
void AndroidMouseMenuButton(int state,int button);

void AndroidMove(float fwd, float strafe);
void AndroidLook(float yaw, float pitch);
void AndroidLookJoystick(float yaw, float pitch);
void AndroidOSD(const char * cmd);

void AndroidAutomapControl(float zoom,float dx,float dy);

void AndroidShowKeyboard(int onf);

void AndroidToggleButtonEditor(void);
#ifdef __cplusplus
}
#endif


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 2010 EDuke32 developers and contributors

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

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

#include "global.h"
#include "game.h"
#include "function.h"
#include "keyboard.h"
#include "mouse.h"
#include "joystick.h"
#include "control.h"
#include "input.h"
#include "menus.h"

int32_t I_CheckAllInput(void)
{
    return KB_KeyWaiting() || MOUSE_GetButtons() || JOYSTICK_GetButtons()
#if defined EDUKE32_IOS
        || g_mouseClickState == MOUSE_PRESSED
#endif
        ;
}

void I_ClearAllInput(void)
{
    KB_FlushKeyboardQueue();
    KB_ClearKeysDown();
    MOUSE_ClearAllButtons();
    JOYSTICK_ClearAllButtons();
    CONTROL_ClearAllButtons();
    mouseAdvanceClickState();
}

void I_ClearLast(void) { CONTROL_ClearUserInput(nullptr); }

int32_t I_TextSubmit(void)
{
    // FIXME: this is needed because the menu code does some weird shit.
    // for some reason, if the mouse cursor is hidden, activating menu items is handled immediately on button press,
    // but if the mouse cursor is visible, activating menu items is handled on button release instead...
    // ...except for the right mouse button, which is handled immediately on button press in both cases.
    if (!MOUSEINACTIVECONDITIONAL(1) || !MOUSEACTIVECONDITIONAL(1))
        MOUSE_ClearButton(M_LEFTBUTTON);

    return CONTROL_GetUserInput(nullptr)->b_advance;
}
int32_t I_ReturnTrigger(void) { return CONTROL_GetUserInput(nullptr)->b_return; }
int32_t I_AdvanceTrigger(void) { return I_TextSubmit() || KB_KeyPressed(sc_Space); }

void I_TextSubmitClear(void) { I_ClearAllInput(); }

void I_AdvanceTriggerClear(void)
{
    I_ClearLast();
    KB_ClearKeyDown(sc_Space);
}

int32_t I_GeneralTrigger(void)
{
    return I_AdvanceTrigger() || I_ReturnTrigger() || I_EscapeTrigger()
#if !defined GEKKO
        || BUTTON(gamefunc_Open)
# if !defined EDUKE32_TOUCH_DEVICES
        || MOUSEINACTIVECONDITIONAL(BUTTON(gamefunc_Fire))
# else
        || BUTTON(gamefunc_Fire)
# endif
#endif
        ;
}

void I_GeneralTriggerClear(void)
{
    I_AdvanceTriggerClear();
//    I_ReturnTriggerClear();

#if !defined GEKKO
    CONTROL_ClearButton(gamefunc_Open);
    CONTROL_ClearButton(gamefunc_Fire);
#endif
}

int32_t I_EscapeTrigger(void) { return CONTROL_GetUserInput(nullptr)->b_escape; }

int32_t I_MenuUp(void)
{
    return CONTROL_GetUserInput(nullptr)->dir == dir_Up || BUTTON(gamefunc_Move_Forward);
}

int32_t I_MenuDown(void)
{
    return CONTROL_GetUserInput(nullptr)->dir == dir_Down || BUTTON(gamefunc_Move_Backward);
}

int32_t I_MenuLeft(void) { return CONTROL_GetUserInput(nullptr)->dir == dir_Left || BUTTON(gamefunc_Turn_Left) || BUTTON(gamefunc_Strafe_Left); }
int32_t I_MenuRight(void) { return CONTROL_GetUserInput(nullptr)->dir == dir_Right || BUTTON(gamefunc_Turn_Right) || BUTTON(gamefunc_Strafe_Right); }

int32_t I_SliderLeft(void) { return I_MenuLeft() || /*MOUSEACTIVECONDITIONAL*/(MOUSE_GetButtons() & M_WHEELDOWN); }
int32_t I_SliderRight(void) { return I_MenuRight() || /*MOUSEACTIVECONDITIONAL*/(MOUSE_GetButtons() & M_WHEELUP); }

int32_t I_PanelUp(void) { return I_MenuUp() || I_MenuLeft() || KB_KeyPressed(sc_PgUp); }
int32_t I_PanelDown(void) { return I_MenuDown() || I_MenuRight() || KB_KeyPressed(sc_PgDn); }

void I_PanelUpClear(void)
{
    I_ClearLast();
    KB_ClearKeyDown(sc_PgUp);
}

void I_PanelDownClear(void)
{
    I_ClearLast();
    KB_ClearKeyDown(sc_PgDn);
}

int32_t I_EnterText(char *t, int32_t maxlength, int32_t flags)
{
    char ch;
    int32_t inputloc = Bstrlen(typebuf);

    while ((ch = KB_GetCh()) != 0)
    {
        if (ch == asc_BackSpace)
        {
            if (inputloc > 0)
            {
                inputloc--;
                *(t+inputloc) = 0;
            }
        }
        else
        {
            if (ch == asc_Enter)
            {
                I_AdvanceTriggerClear();
                return 1;
            }
            else if (ch == asc_Escape)
            {
                I_ReturnTriggerClear();
                return -1;
            }
            else if (ch >= 32 && inputloc < maxlength && ch < 127)
            {
                if (!(flags & INPUT_NUMERIC) || (ch >= '0' && ch <= '9'))
                {
                    // JBF 20040508: so we can have numeric only if we want
                    *(t+inputloc) = ch;
                    *(t+inputloc+1) = 0;
                    inputloc++;
                }
            }
        }
    }

    if (I_TextSubmit())
    {
        I_TextSubmitClear();
        return 1;
    }
    if (I_ReturnTrigger())
    {
        I_ReturnTriggerClear();
        return -1;
    }

    return 0;
}


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 2010 EDuke32 developers and contributors

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

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

#ifndef input_h_
#define input_h_

extern int32_t I_CheckAllInput(void);
extern void I_ClearAllInput(void);
extern void I_ClearLast(void);

// Advance = Selecting a menu option || Saying "Yes" || Going forward in Help/Credits
// Return = Closing a sub-menu || Saying "No"
// General = Advance + Return = Skipping screens
// Escape = Opening the menu in-game (should not be any gamefuncs)

extern int32_t I_AdvanceTrigger(void);
extern int32_t I_GeneralTrigger(void);
extern int32_t I_ReturnTrigger(void);
extern int32_t I_EscapeTrigger(void);

extern void I_AdvanceTriggerClear(void);
extern void I_GeneralTriggerClear(void);

#define I_ReturnTriggerClear I_ClearLast
#define I_EscapeTriggerClear I_ClearLast

extern int32_t I_MenuUp(void);
extern int32_t I_MenuDown(void);
extern int32_t I_MenuLeft(void);
extern int32_t I_MenuRight(void);

#define I_MenuUpClear    I_ClearLast
#define I_MenuDownClear  I_ClearLast
#define I_MenuLeftClear  I_ClearLast
#define I_MenuRightClear I_ClearLast

extern int32_t I_PanelUp(void);
extern int32_t I_PanelDown(void);

extern void I_PanelUpClear(void);
extern void I_PanelDownClear(void);

extern int32_t I_SliderLeft(void);
extern int32_t I_SliderRight(void);

#define I_SliderLeftClear  I_ClearLast
#define I_SliderRightClear I_ClearLast

enum EnterTextFlags_t {
    INPUT_NUMERIC        = 0x00000001,
};

extern int32_t I_EnterText(char *t, int32_t maxlength, int32_t flags);

#define FF_WEAPON_MAX_TIME 66
#define FF_WEAPON_DMG_MIN  10
#define FF_WEAPON_DMG_MAX  50

#define FF_WEAPON_DMG_SCALE  8
#define FF_WEAPON_TIME_SCALE 3

#define FF_PLAYER_DMG_SCALE  10
#define FF_PLAYER_TIME_SCALE 4

static FORCE_INLINE void I_AddForceFeedback(int const lo, int const hi, int const time)
{
    if (!joystick.hasRumble || !ud.config.controllerRumble)
        return;

    joystick.rumbleHigh = min<int>(UINT16_MAX, joystick.rumbleHigh + hi);
    joystick.rumbleLow  = min<int>(UINT16_MAX, joystick.rumbleLow + lo);
    joystick.rumbleTime = max<int>(time, joystick.rumbleTime);
}

#endif


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 2016 EDuke32 developers and contributors

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

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

#pragma once

enum dukeinv_t
{
    GET_STEROIDS,  // 0
    GET_SHIELD,
    GET_SCUBA,
    GET_HOLODUKE,
    GET_JETPACK,
    GET_DUMMY1,  // 5
    GET_ACCESS,
    GET_HEATS,
    GET_DUMMY2,
    GET_FIRSTAID,
    GET_BOOTS,  // 10
    GET_MAX
};

// these are not in the same order as the above, and it can't be changed for compat reasons. lame!
enum dukeinvicon_t
{
    ICON_NONE,  // 0
    ICON_FIRSTAID,
    ICON_STEROIDS,
    ICON_HOLODUKE,
    ICON_JETPACK,
    ICON_HEATS,  // 5
    ICON_SCUBA,
    ICON_BOOTS,
    ICON_MAX
};

extern int const icon_to_inv[ICON_MAX];

extern int const inv_to_icon[GET_MAX];

enum dukeweapon_t
{
    KNEE_WEAPON,  // 0
    PISTOL_WEAPON,
    SHOTGUN_WEAPON,
    CHAINGUN_WEAPON,
    RPG_WEAPON,
    HANDBOMB_WEAPON,  // 5
    SHRINKER_WEAPON,
    DEVISTATOR_WEAPON,
    TRIPBOMB_WEAPON,
    FREEZE_WEAPON,
    HANDREMOTE_WEAPON,  // 10
    GROW_WEAPON,
    FLAMETHROWER_WEAPON,
    MAX_WEAPONS
};


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 2010 EDuke32 developers and contributors

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

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

#ifndef KEYS_H

#define KEYS_H

   #define NUM_CODES     128

   #define ESC    0x1B
   #define ENTER  0x0D

   #define KEYSC_ESC	  0x01
   #define KEYSC_1  	  0x02
   #define KEYSC_2  	  0x03
   #define KEYSC_3  	  0x04
   #define KEYSC_4  	  0x05
   #define KEYSC_5  	  0x06
   #define KEYSC_6  	  0x07
   #define KEYSC_7  	  0x08
   #define KEYSC_8  	  0x09
   #define KEYSC_9  	  0x0a
   #define KEYSC_0  	  0x0b
   #define KEYSC_DASH     0x0c
   #define KEYSC_EQUAL    0x0d

   #define KEYSC_BS 	  0x0e
   #define KEYSC_TAB	  0x0f
   #define KEYSC_Q  	  0x10
   #define KEYSC_W  	  0x11
   #define KEYSC_E  	  0x12
   #define KEYSC_R  	  0x13
   #define KEYSC_T  	  0x14
   #define KEYSC_Y  	  0x15
   #define KEYSC_U  	  0x16
   #define KEYSC_I  	  0x17
   #define KEYSC_O  	  0x18
   #define KEYSC_P  	  0x19
   #define KEYSC_LBRACK   0x1a
   #define KEYSC_RBRACK   0x1b
   #define KEYSC_ENTER    0x1c

   #define KEYSC_LCTRL    0x1d
   #define KEYSC_A  	  0x1e
   #define KEYSC_S  	  0x1f
   #define KEYSC_D  	  0x20
   #define KEYSC_F  	  0x21
   #define KEYSC_G  	  0x22
   #define KEYSC_H  	  0x23
   #define KEYSC_J  	  0x24
   #define KEYSC_K  	  0x25
   #define KEYSC_L  	  0x26
   #define KEYSC_SEMI     0x27
   #define KEYSC_QUOTE    0x28
   #define KEYSC_BQUOTE   0x29
   #define KEYSC_TILDE    0x29

   #define KEYSC_LSHIFT   0x2a
   #define KEYSC_BSLASH   0x2b
   #define KEYSC_Z  	  0x2c
   #define KEYSC_X  	  0x2d
   #define KEYSC_C  	  0x2e
   #define KEYSC_V  	  0x2f
   #define KEYSC_B  	  0x30
   #define KEYSC_N  	  0x31
   #define KEYSC_M  	  0x32
   #define KEYSC_COMMA    0x33
   #define KEYSC_PERIOD   0x34
   #define KEYSC_SLASH    0x35
   #define KEYSC_RSHIFT   0x36
   #define KEYSC_gSTAR    0x37

   #define KEYSC_LALT     0x38
   #define KEYSC_SPACE    0x39
   #define KEYSC_CAPS     0x3a

   #define KEYSC_F1 	  0x3b
   #define KEYSC_F2 	  0x3c
   #define KEYSC_F3 	  0x3d
   #define KEYSC_F4 	  0x3e
   #define KEYSC_F5 	  0x3f
   #define KEYSC_F6 	  0x40
   #define KEYSC_F7 	  0x41
   #define KEYSC_F8 	  0x42
   #define KEYSC_F9 	  0x43
   #define KEYSC_F10	  0x44

   #define KEYSC_gNUM     0x45
   #define KEYSC_SCROLL   0x46

   #define KEYSC_gHOME    0x47
   #define KEYSC_gUP	  0x48
   #define KEYSC_gPGUP    0x49
   #define KEYSC_gMINUS   0x4a
   #define KEYSC_gLEFT    0x4b
   #define KEYSC_gKP5     0x4c
   #define KEYSC_gRIGHT   0x4d
   #define KEYSC_gPLUS    0x4e
   #define KEYSC_gEND     0x4f
   #define KEYSC_gDOWN    0x50
   #define KEYSC_gPGDN    0x51
   #define KEYSC_gINS     0x52
   #define KEYSC_gDEL     0x53

   #define KEYSC_F11    0x57
   #define KEYSC_F12    0x58

   #define KEYSC_gENTER   0x9C
   #define KEYSC_RCTRL    0x9D
   #define KEYSC_gSLASH   0xB5
   #define KEYSC_RALT     0xB8
   #define KEYSC_PRTSCN   0xB7
   #define KEYSC_PAUSE    0xC5
   #define KEYSC_HOME     0xC7
   #define KEYSC_UP 	  0xC8
   #define KEYSC_PGUP     0xC9
   #define KEYSC_LEFT     0xCB
   #define KEYSC_RIGHT    0xCD
   #define KEYSC_END	  0xCF
   #define KEYSC_DOWN     0xD0
   #define KEYSC_PGDN     0xD1
   #define KEYSC_INSERT   0xD2
   #define KEYSC_DELETE   0xD3

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

#endif