Fork the vendored engine into the playable replica

Engine changes vs the vendored upstream (full ledger in
docs/upstream-patches.md):

- Assets: replace the encrypted FILE000N.GLB archives with a catalog of
  pre-decrypted loose files (data/INDEX); GLB_SlotItems() drives
  mission-pack / registered-version detection; payloads never run the
  GLB cipher at runtime.
- Platform: Linux/SDL2/ALSA only; Android, MSVC/MinGW, macOS packaging,
  bundled Windows SDL2 SDKs and the ENDOOM exit screen are gone;
  EXIT_Error now prints before exiting.
- Rendering: decouple presentation from simulation -- sim stays at the
  original 70/3 Hz, frames render interpolated at display rate (player,
  map scroll, enemies, shots, bonuses, anims, shadows); menus keep 70 Hz
  pacing; vsync with a delay-guard fallback.
- QoL: borderless window mode (Video/borderless), no menu cursor
  snapping onto default buttons.

Fix four regressions from the render split:

- Shield bars never redrew: RAP_ThinkStats latches g_oldshield each sim
  step before RAP_DisplayStats' dirty check could fire. Bars now draw
  unconditionally per rendered frame; g_oldsuper deleted, g_oldshield
  kept as sim-side damage-detection state only.
- Dying ships despawned without exploding: the render loop never called
  ANIMS_DisplayHigh(); most air-death explosions register HIGH_AIR.
  Restored between the player and enemy shots, as upstream orders it.
- Laser turret broke: reusing doneflag as a draw marker (it is
  hit/retire game state, and the turret retire path never frees its
  shot) hid the beam on hitting ticks and leaked one SHOTS pool slot
  per fire until no weapon could shoot. S_LINE tracers now carry an age
  counter: one Think pass, every render of their birth step, purged at
  the top of the next Think.
- Muzzle flash was cleared per rendered frame, making it invisible at
  display refresh rates; now cleared once per simulation step.
This commit is contained in:
raptorreplica committed 2026-08-26 18:45:07 +10:00
1 parent f7c9b7a02d
commit 214789fe87
667 files changed
+1490 -279572

No files matched your search

+29 -6
View File
@@ -253,6 +253,8 @@ ANIMS_StartAnim(
cur->x = x - lib->xoff;
cur->y = y - lib->yoff;
cur->groundflag = lib->groundflag;
cur->dx = cur->pdx = cur->x;
cur->dy = cur->pdy = cur->y;
}
/***************************************************************************
@@ -275,6 +277,8 @@ ANIMS_StartGAnim(
cur->x = x;
cur->y = y;
cur->groundflag = 0;
cur->dx = cur->pdx = cur->x;
cur->dy = cur->pdy = cur->y;
}
/***************************************************************************
@@ -301,6 +305,8 @@ ANIMS_StartEAnim(
cur->x = x - lib->xoff;
cur->y = y - lib->yoff;
cur->groundflag = HIGH_AIR;
cur->dx = cur->pdx = cur->x;
cur->dy = cur->pdy = cur->y;
}
/***************************************************************************
@@ -325,6 +331,8 @@ ANIMS_StartAAnim(
cur->x = x - lib->xoff;
cur->y = y - lib->yoff;
cur->groundflag = HIGH_AIR;
cur->dx = cur->pdx = cur->x;
cur->dy = cur->pdy = cur->y;
}
/***************************************************************************
@@ -342,6 +350,9 @@ ANIMS_Think(
{
lib = cur->lib;
cur->pdx = cur->dx;
cur->pdy = cur->dy;
if (cur->curframe >= lib->numframes)
{
cur = ANIMS_Remove(cur);
@@ -403,18 +414,22 @@ ANIMS_DisplayGround(
{
ANIMS *cur;
char *pic;
int idx, idy;
for (cur = first_anims.next; &last_anims != cur; cur = cur->next)
{
if (cur->groundflag)
continue;
idx = GFX_InterpCoord(cur->dx, cur->pdx);
idy = GFX_InterpCoord(cur->dy, cur->pdy);
pic = (char*)GLB_GetItem(cur->item);
if (cur->lib->transparent)
GFX_ShadeShape(LIGHT, pic, cur->dx, cur->dy);
GFX_ShadeShape(LIGHT, pic, idx, idy);
else
GFX_PutSprite(pic, cur->dx, cur->dy);
GFX_PutSprite(pic, idx, idy);
}
}
@@ -428,19 +443,23 @@ ANIMS_DisplaySky(
{
ANIMS *cur;
char *pic;
int idx, idy;
for (cur = first_anims.next; &last_anims != cur; cur = cur->next)
{
if (cur->groundflag != MID_AIR)
continue;
idx = GFX_InterpCoord(cur->dx, cur->pdx);
idy = GFX_InterpCoord(cur->dy, cur->pdy);
pic = (char*)GLB_GetItem(cur->item);
if (cur->lib->transparent)
GFX_ShadeShape(LIGHT, pic, cur->dx, cur->dy);
GFX_ShadeShape(LIGHT, pic, idx, idy);
else
GFX_PutSprite(pic, cur->dx, cur->dy);
GFX_PutSprite(pic, idx, idy);
}
}
@@ -454,17 +473,21 @@ ANIMS_DisplayHigh(
{
ANIMS *cur;
char *pic;
int idx, idy;
for (cur = first_anims.next; &last_anims != cur; cur = cur->next)
{
if (cur->groundflag != HIGH_AIR)
continue;
idx = GFX_InterpCoord(cur->dx, cur->pdx);
idy = GFX_InterpCoord(cur->dy, cur->pdy);
pic = (char*)GLB_GetItem(cur->item);
if (cur->lib->transparent)
GFX_ShadeShape(LIGHT, pic, cur->dx, cur->dy);
GFX_ShadeShape(LIGHT, pic, idx, idy);
else
GFX_PutSprite(pic, cur->dx, cur->dy);
GFX_PutSprite(pic, idx, idy);
}
}
+2
View File
@@ -35,6 +35,8 @@ typedef struct ANIMS_S
int item;
int dx;
int dy;
int pdx; // PREV SIM DX (INTERP)
int pdy; // PREV SIM DY (INTERP)
int x;
int y;
int curframe;
+23 -3
View File
@@ -162,6 +162,15 @@ BONUS_Add(
cur->x = MAP_LEFT + x;
cur->y = y;
cur->pos = wrand() % 16;
cur->bx = cur->x - (BONUS_WIDTH / 2) + xpos[cur->pos];
cur->by = cur->y - (BONUS_HEIGHT / 2) + ypos[cur->pos];
cur->gx = cur->x - (glow_lx>>1) + xpos[cur->pos];
cur->gy = cur->y - (glow_ly>>1) + ypos[cur->pos];
cur->pbx = cur->bx;
cur->pby = cur->by;
cur->pgx = cur->gx;
cur->pgy = cur->gy;
}
/***************************************************************************
@@ -183,6 +192,11 @@ BONUS_Think(
for (cur = first_bonus.next; &last_bonus != cur; cur = cur->next)
{
cur->pbx = cur->bx;
cur->pby = cur->by;
cur->pgx = cur->gx;
cur->pgy = cur->gy;
cur->item = cur->lib->item + cur->curframe;
cur->bx = cur->x - (BONUS_WIDTH / 2) + xpos[cur->pos];
@@ -264,16 +278,22 @@ BONUS_Display(
)
{
BONUS *cur;
int ibx, iby, igx, igy;
for (cur = first_bonus.next; &last_bonus != cur; cur = cur->next)
{
ibx = GFX_InterpCoord(cur->bx, cur->pbx);
iby = GFX_InterpCoord(cur->by, cur->pby);
igx = GFX_InterpCoord(cur->gx, cur->pgx);
igy = GFX_InterpCoord(cur->gy, cur->pgy);
if (!cur->dflag)
{
GFX_PutSprite((char*)GLB_GetItem(cur->item), cur->bx, cur->by);
GFX_ShadeShape(LIGHT, (char*)GLB_GetItem(glow[cur->curglow]), cur->gx, cur->gy);
GFX_PutSprite((char*)GLB_GetItem(cur->item), ibx, iby);
GFX_ShadeShape(LIGHT, (char*)GLB_GetItem(glow[cur->curglow]), igx, igy);
}
else
GFX_PutSprite((char*)GLB_GetItem(FILE10f_N$_PIC), cur->bx, cur->by);
GFX_PutSprite((char*)GLB_GetItem(FILE10f_N$_PIC), ibx, iby);
}
}
+4
View File
@@ -21,6 +21,10 @@ typedef struct BONUS_S
int by; // BONUS Y POSITION
int gx; // GLOW X POSITION
int gy; // GLOW Y POSITION
int pbx; // PREV SIM BX (INTERP)
int pby; // PREV SIM BY (INTERP)
int pgx; // PREV SIM GX (INTERP)
int pgy; // PREV SIM GY (INTERP)
int pos; // POS IN CIRCLE
int dflag; // DONEFLAG
int countdown; // COUNTDOWN TO REMOVE
+9 -1
View File
@@ -1,9 +1,17 @@
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
static inline void EXIT_Error(const char *a1, ...)
{
exit(0);
va_list args;
va_start(args, a1);
vfprintf(stderr, a1, args);
va_end(args);
fputc('\n', stderr);
exit(0);
}
static inline void EXIT_Clean(void)
+16 -5
View File
@@ -713,6 +713,10 @@ void ENEMY_Think(
{
curlib = sprite->lib;
sprite->px = sprite->x;
sprite->py = sprite->y;
sprite->eframe ^= 1;
if (LE_LONG(curlib->num_frames) > 1)
{
sprite->item = LE_LONG(curlib->item) + sprite->curframe;
@@ -1177,12 +1181,17 @@ ENEMY_DisplayGround(
)
{
SPRITE_SHIP *spt;
int ix, iy;
for (spt = first_enemy.next; &last_enemy != spt; spt = spt->next)
{
if (!spt->groundflag)
continue;
GFX_PutSprite((char*)GLB_GetItem(spt->item), spt->x, spt->y);
ix = GFX_InterpCoord(spt->x, spt->px);
iy = GFX_InterpCoord(spt->y, spt->py);
GFX_PutSprite((char*)GLB_GetItem(spt->item), ix, iy);
}
}
@@ -1195,6 +1204,7 @@ ENEMY_DisplaySky(
)
{
int i;
int ix, iy;
SPRITE_SHIP *spt;
for (spt = first_enemy.next; &last_enemy != spt; spt = spt->next)
@@ -1202,14 +1212,15 @@ ENEMY_DisplaySky(
if (spt->groundflag)
continue;
GFX_PutSprite((char*)GLB_GetItem(spt->item), spt->x, spt->y);
ix = GFX_InterpCoord(spt->x, spt->px);
iy = GFX_InterpCoord(spt->y, spt->py);
GFX_PutSprite((char*)GLB_GetItem(spt->item), ix, iy);
for (i = 0; i < LE_LONG(spt->lib->numengs); i++)
{
FLAME_Up(spt->x + LE_SHORT(spt->lib->engx[i]), spt->y + LE_SHORT(spt->lib->engy[i]), LE_SHORT(spt->lib->englx[i]), spt->eframe);
FLAME_Up(ix + LE_SHORT(spt->lib->engx[i]), iy + LE_SHORT(spt->lib->engy[i]), LE_SHORT(spt->lib->englx[i]), spt->eframe);
}
spt->eframe ^= 1;
}
}
+2
View File
@@ -77,6 +77,8 @@ typedef struct SPRITE_SHIP_S
int sy; // START Y
int x; // CENTER X POS;
int y; // Y POS
int px; // PREV SIM CENTER X (INTERP)
int py; // PREV SIM Y POS (INTERP)
int x2; // WIDTH
int y2; // HEIGHT
int width; // WIDTH
+17 -6
View File
@@ -372,6 +372,11 @@ ESHOT_Shoot(
InitMobj(&cur->move);
MoveSobj(&cur->move, 1);
cur->x = cur->move.x;
cur->y = cur->move.y;
cur->px = cur->x;
cur->py = cur->y;
if (cur->move.x < 0 || cur->move.x >= 320)
cur->move.done = 1;
@@ -399,6 +404,9 @@ ESHOT_Think(
{
lib = shot->lib;
shot->px = shot->x;
shot->py = shot->y;
shot->pic = lib->pic[shot->curframe];
shot->curframe++;
@@ -512,17 +520,20 @@ ESHOT_Display(
)
{
ESHOT *shot;
int loop, y;
int loop, y, ix, iy;
GFX_PIC *h;
for (shot = first_eshot.next; shot !=&last_eshot; shot = shot->next)
{
ix = GFX_InterpCoord(shot->x, shot->px);
iy = GFX_InterpCoord(shot->y, shot->py);
if (shot->type == ES_LASER)
{
for (loop = shot->y; loop < shot->move.y2; loop += 3)
GFX_PutSprite(shot->pic, shot->x, loop);
for (loop = iy; loop < shot->move.y2; loop += 3)
GFX_PutSprite(shot->pic, ix, loop);
GFX_PutSprite(elaspow[shot->curframe - 1], shot->x, shot->y);
GFX_PutSprite(elaspow[shot->curframe - 1], ix, iy);
h = (GFX_PIC*)lashit[shot->curframe - 1];
@@ -530,10 +541,10 @@ ESHOT_Display(
if (y > 0 && y < 200)
{
GFX_PutSprite((char*)h, shot->x - (LE_LONG(h->width) >> 2), y);
GFX_PutSprite((char*)h, ix - (LE_LONG(h->width) >> 2), y);
}
}
else
GFX_PutSprite(shot->pic, shot->x, shot->y);
GFX_PutSprite(shot->pic, ix, iy);
}
}
+2
View File
@@ -36,6 +36,8 @@ typedef struct ESHOT_S
int curframe; // CURRENT ANIM FRAME
int x; // CUR SHOT CENTER X
int y; // CUR SHOT CENTER Y
int px; // PREV SIM X (INTERP)
int py; // PREV SIM Y (INTERP)
MOVEOBJ move; // MOVE STUFF
int doneflag; // SHOT DONE = TRUE
ESHOT_LIB *lib; // POINTER TO LIB
+32
View File
@@ -112,6 +112,38 @@ GFX_GetFrameCount(
return framecount;
}
/***************************************************************************
GFX_SetInterp () - Sets the interpolation fraction (num/den, 0 <= num <=
den) used by GFX_InterpCoord() for this rendered frame.
***************************************************************************/
static int gfx_interp_num = 1, gfx_interp_den = 1;
void
GFX_SetInterp(
int num, // INPUT : interpolated fraction numerator
int den // INPUT : interpolated fraction denominator
)
{
if (den > 0 && num >= 0)
{
gfx_interp_num = num;
gfx_interp_den = den;
}
}
/***************************************************************************
GFX_InterpCoord () - Interpolates between previous and current simulation
position: prev + (cur - prev) * num/den.
***************************************************************************/
int
GFX_InterpCoord(
int cur, // INPUT : current sim position
int prev // INPUT : previous sim position
)
{
return prev + (int)(((long long)(cur - prev) * gfx_interp_num) / gfx_interp_den);
}
/*************************************************************************
GFX_ClipLines ()
*************************************************************************/
+2
View File
@@ -81,6 +81,8 @@ void GFX_UpdateTimer(void);
void GFX_InitSystem(void);
void GFX_InitVideo(char *curpal);
int GFX_GetFrameCount(void);
void GFX_SetInterp(int num, int den);
int GFX_InterpCoord(int cur, int prev);
int GFX_ClipLines(char **image, int *x, int *y, int *lx, int *ly);
void GFX_SetPalette(char *curpal, int startpal);
void GFX_FadeOut(int red, int green, int blue, int speed);
+136 -199
View File
@@ -5,6 +5,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/stat.h>
#include "common.h"
#include "glbapi.h"
#include "vmemapi.h"
@@ -31,13 +32,10 @@ char* strupr(char* s)
#define PATH_MAX MAX_PATH
#endif // _MSC_VER
#define _SCOTTGAME
static const char* serial = "32768GLB";
static char exePath[PATH_MAX];
static int num_glbs;
static KEYFILE g_key;
static char prefix[5] = "FILE";
static bool fVmem = 0;
/*
@@ -55,11 +53,8 @@ typedef struct
typedef struct
{
char filepath[PATH_MAX];
ITEMINFO* item;
int items;
FILE *handle;
const char *permissions;
}FILEDESC;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
@@ -153,207 +148,155 @@ GLB_DeCrypt(
}
/*------------------------------------------------------------------------
GLB_FindFile() - Finds a file, opens it, and stores it's path
Data catalog: INDEX maps asset ids to files in category dirs
(music/, sprites/, ... — see tools/glbextract.py). Ids are engine
handles, (archive slot << 16) | item index, sorted ascending.
------------------------------------------------------------------------*/
static FILE*
GLB_FindFile(
int return_on_failure, // INPUT : Don't bomb if file not open
int filenum, // INPUT : file number
const char *permissions // INPUT : file access permissions
)
typedef struct
{
const char* routine = "GLB_FindFile";
char filename[PATH_MAX];
char filenamelc[PATH_MAX];
FILE *handle;
FILEDESC* fd;
/*
* Scott, the ASSERT function is a macro that will be compiled-out when
* not debugging ( DEBUG not defined ), otherwise it calls EXIT_Assert
* if the expression is false ( which bails out of your program and displays
* the expression, file & line number of the assertion ). This is a standard
* way of checking variables for correct boundries during development, and
* makes it easy to remove extra logic for doing so by recompiling without
* DEBUG defined.
*/
ASSERT(filenum >= 0 && filenum < MAX_GLB_FILES);
/*
* create a file name and attempt to open it local first, then if it
* fails use the exe path and try again.
*/
sprintf(filenamelc, "%s%04u.glb", "file", filenum);
if (!access(filenamelc, 0))
strcpy(filename, filenamelc);
else
sprintf(filename, "%s%04u.GLB", prefix, filenum);
if ((handle = fopen(filename, permissions)) == NULL)
{
sprintf(filenamelc, "%s%s%04u.glb", exePath, "file", filenum);
if (!access(filenamelc, 0))
strcpy(filename, filenamelc);
else
sprintf(filename, "%s%s%04u.GLB", exePath, prefix, filenum);
if ((handle = fopen(filename, permissions)) == NULL)
{
if (return_on_failure)
return NULL;
uint32_t id;
uint32_t size;
char path[64];
}CATENTRY;
sprintf(filename, "%s%04u.GLB", prefix, filenum);
EXIT_Error("GLB_FindFile: %s, Error #%d,%s",
filename, errno, strerror(errno));
}
}
/*
* Keep file handle
*/
fd = &filedesc[filenum];
strcpy(fd->filepath, filename);
fd->permissions = permissions;
fd->handle = handle;
return handle;
}
static CATENTRY* catalog;
static int catalog_n;
static char dataRoot[PATH_MAX]; // "" when INDEX sits in the cwd
/*------------------------------------------------------------------------
GLB_OpenFile() - Opens & Caches file handle
------------------------------------------------------------------------*/
static FILE*
GLB_OpenFile(
int return_on_failure, // INPUT : Don't bomb if file not open
int filenum, // INPUT : file number
const char *permissions // INPUT : file access permissions
)
{
FILEDESC* fd;
ASSERT(filenum >= 0 && filenum < MAX_GLB_FILES);
fd = &filedesc[filenum];
if (fd->handle == 0)
return GLB_FindFile(return_on_failure, filenum, permissions);
else if (fd->permissions != permissions)
{
fclose(fd->handle);
if ((fd->handle = fopen(fd->filepath, permissions)) == NULL)
{
if (return_on_failure)
return NULL;
EXIT_Error("GLB_OpenFile: %s, Error #%d,%s",
fd->filepath, errno, strerror(errno));
}
}
else
{
fseek(fd->handle, 0L, SEEK_SET);
}
return fd->handle;
}
/*------------------------------------------------------------------------
GLB_CloseFiles() - Closes all cached files.
GLB_LoadCatalog() - Parses INDEX (current directory first, then
exePath). Missing INDEX leaves the catalog empty; every slot then
reports zero items, which callers treat as "no data".
------------------------------------------------------------------------*/
static void
GLB_CloseFiles(
GLB_LoadCatalog(
void
)
{
int j;
char path[PATH_MAX];
FILE *handle;
for (j = 0; j < MAX_GLB_FILES; j++)
if (catalog != NULL)
return;
strcpy(dataRoot, "");
handle = fopen("INDEX", "rb");
if (handle == NULL)
{
if (filedesc[j].handle)
{
fclose(filedesc[j].handle);
filedesc[j].handle = 0;
}
strcpy(dataRoot, exePath);
sprintf(path, "%sINDEX", exePath);
handle = fopen(path, "rb");
}
if (handle == NULL)
return;
while (true)
{
CATENTRY ce;
if (fscanf(handle, "%x %u %63s", &ce.id, &ce.size, ce.path) != 3)
break;
catalog = (CATENTRY*)realloc(catalog, (catalog_n + 1) * sizeof(CATENTRY));
if (catalog == NULL)
EXIT_Error("GLB_LoadCatalog: memory");
catalog[catalog_n++] = ce;
}
fclose(handle);
}
/***************************************************************************
GLB_SlotItems() - Returns number of catalog items in one archive slot
***************************************************************************/
int
GLB_SlotItems(
int filenum // INPUT : archive slot number
)
{
int i;
int count;
GLB_LoadCatalog();
count = 0;
for (i = 0; i < catalog_n; i++)
{
if (catalog[i].id >> 16 == (uint32_t)filenum)
count++;
}
return count;
}
/*------------------------------------------------------------------------
GLB_NumItems() - Returns number of items in a .GLB file
GLB_CatFind() - Binary search of the catalog by asset id.
------------------------------------------------------------------------*/
static int
GLB_NumItems(
int filenum
static CATENTRY*
GLB_CatFind(
uint32_t id
)
{
KEYFILE key;
FILE *handle;
int lo;
int hi;
ASSERT(filenum >= 0 && filenum < num_glbs);
lo = 0;
hi = catalog_n - 1;
handle = GLB_OpenFile(1, filenum, "rb");
if (handle == NULL)
return 0;
fseek(handle, 0L, SEEK_SET);
if (!fread(&key, sizeof(KEYFILE), 1, handle))
while (lo <= hi)
{
EXIT_Error("GLB_NumItems: Read failed!");
int mid = (lo + hi) / 2;
if (catalog[mid].id == id)
return &catalog[mid];
else if (catalog[mid].id < id)
lo = mid + 1;
else
hi = mid - 1;
}
#ifdef _SCOTTGAME
GLB_DeCrypt(serial, (uint8_t*)&key, sizeof(KEYFILE));
#endif
return ((int)LE_ULONG(key.offset));
EXIT_Error("GLB_CatFind: id %x not in catalog", id);
return NULL;
}
/*--------------------------------------------------------------------------
GLB_LoadIDT() Loads a item descriptor table from a GLB file.
GLB_FillSlot() - Fills one slot's item descriptors from the catalog.
Extracted payloads are stored pre-decrypted, so no item stays flagged
ITF_ENCODED.
--------------------------------------------------------------------------*/
static void
GLB_LoadIDT(
FILEDESC* fd // INPUT: file to load
GLB_FillSlot(
FILEDESC* fd, // INPUT: slot descriptor to fill
int filenum // INPUT : archive slot number
)
{
FILE *handle;
int j;
int k;
int n;
KEYFILE key[10];
ITEMINFO* ii;
int i;
int n;
handle = fd->handle;
n = 0;
ii = fd->item;
fseek(handle, sizeof(KEYFILE), SEEK_SET);
for (j = 0; j < fd->items; )
for (i = 0; i < catalog_n && n < fd->items; i++)
{
k = fd->items - j;
if (k > ASIZE(key))
k = ASIZE(key);
CATENTRY* ce = &catalog[i];
const char* base;
fread(key, sizeof(KEYFILE), k, handle);
for (n = 0; n < k; n++)
{
#ifdef _SCOTTGAME
GLB_DeCrypt(serial, (void*)&key[n], sizeof(KEYFILE));
#endif
if (LE_ULONG(key[n].opt) == GLB_ENCODED)
ii->flags |= ITF_ENCODED;
if (ce->id >> 16 != (uint32_t)filenum)
continue;
ii->size = LE_ULONG(key[n].filesize);
ii->offset = LE_ULONG(key[n].offset);
memcpy(ii->name, key[n].name, sizeof(ii->name));
ii++;
}
j += k;
base = strrchr(ce->path, '/');
base = (base != NULL) ? base + 1 : ce->path;
if (strlen(base) >= sizeof(ii->name))
EXIT_Error("GLB_FillSlot: item name too long: %s", base);
strcpy(ii->name, base);
ii->size = ce->size;
ii++;
n++;
}
}
@@ -396,39 +339,32 @@ GLB_InitSystem(
num_glbs = innum;
ASSERT(num_glbs >= 1 && num_glbs <= MAX_GLB_FILES);
if (iprefix)
{
ASSERT(strlen(iprefix) < sizeof(prefix) - 1);
strcpy(prefix, iprefix);
strupr(prefix);
}
(void)iprefix; // archive-name prefixes are obsolete with the catalog
memset(filedesc, 0, sizeof(filedesc));
/*
* Next, read in header of each file and allocate cache
* Parse the catalog, then set up one descriptor per non-empty slot
*/
GLB_LoadCatalog();
opened = 0;
for (filenum = 0; filenum < num_glbs; filenum++)
{
fd = &filedesc[filenum];
if ((num = GLB_NumItems(filenum)) != 0)
if ((num = GLB_SlotItems(filenum)) != 0)
{
fd->items = num;
/*
* Note: calloc zeros out all memory that it allocates
*/
fd->item = (ITEMINFO*)calloc(num, sizeof(ITEMINFO));
if (fd->item == NULL)
EXIT_Error("GLB_NumItems: memory ( init )");
/*
* Load Item Descriptor Table for file
*/
GLB_LoadIDT(fd);
EXIT_Error("GLB_InitSystem: memory ( init )");
GLB_FillSlot(fd, filenum);
opened++;
}
}
@@ -446,14 +382,13 @@ GLB_Load(
int itemnum // INPUT: item in file number
)
{
FILE *handle;
ITEMINFO* ii;
char path[PATH_MAX];
FILE *f;
ASSERT(filenum >= 0 && filenum < num_glbs);
handle = filedesc[filenum].handle;
if (handle == 0)
if (filedesc[filenum].item == NULL)
return 0;
ASSERT(itemnum < (WORD)filedesc[filenum].items);
@@ -467,14 +402,16 @@ GLB_Load(
memcpy(inmem, ii->vm_mem.obj, ii->size);
else
{
fseek(handle, ii->offset, SEEK_SET);
fread(inmem, ii->size, 1, handle);
#ifdef _SCOTTGAME
if (ii->flags & ITF_ENCODED)
{
GLB_DeCrypt(serial, inmem, ii->size);
}
#endif
CATENTRY* ce = GLB_CatFind(((uint32_t)filenum << 16) | (uint32_t)itemnum);
char path[PATH_MAX];
sprintf(path, "%s%s", dataRoot, ce->path);
f = fopen(path, "rb");
if (f == NULL || fread(inmem, ii->size, 1, f) != 1)
EXIT_Error("GLB_Load: read failed on %s", path);
fclose(f);
}
}
+1
View File
@@ -23,6 +23,7 @@ typedef struct
void GLB_UseVM(void);
int GLB_InitSystem(const char *exepath, int innum, const char *iprefix);
int GLB_SlotItems(int filenum);
char *GLB_LockItem(int handle);
void GLB_UnlockItem(int handle);
char *GLB_GetItem(int handle);
-86
View File
@@ -1,86 +0,0 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program 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.
//
// DESCRIPTION:
// Exit text-mode ENDOOM screen.
//
#include <stdio.h>
#include <string.h>
#include "rap.h"
#include "i_lastscr.h"
#include "textscreen.h"
#include "i_video.h"
#include "joyapi.h"
#include "kbdapi.h"
#include "ptrapi.h"
#include "imsapi.h"
#define LASTSCR_W 80
#define LASTSCR_H 25
//
// Displays the text mode ending screen after the game quits
//
void I_LASTSCR(char* mem)
{
unsigned char* screendata;
int y;
int indent;
TXT_Fullscreen(txt_fullscreen);
// Set up text mode screen
TXT_Init();
TXT_SetWindowTitle("Raptor");
// SDL2-TODO I_InitWindowTitle();
// SDL2-TODO I_InitWindowIcon();
// Write the data to the screen memory
screendata = TXT_GetScreenData();
indent = (LASTSCR_W - TXT_SCREEN_W) / 2;
for (y = 0; y < TXT_SCREEN_H; ++y)
{
memcpy(screendata + (y * TXT_SCREEN_W * 2),
mem + (y * LASTSCR_W + indent) * 2,
TXT_SCREEN_W * 2);
}
// Wait for a keypress
IMS_StartAck();
I_Settextmode(true);
while (true)
{
TXT_UpdateScreen();
I_GetEvent();
if (joy_ack || kbd_ack || mouse_b1_ack || mouse_b2_ack || mouse_b3_ack)
break;
TXT_Sleep(0);
}
// Shut down text mode screen
TXT_Shutdown();
}
-3
View File
@@ -1,3 +0,0 @@
#pragma once
void I_LASTSCR(char* mem);
+89 -13
View File
@@ -84,6 +84,10 @@ static bool initialized = false;
static bool nomouse = false;
int usemouse = 1;
// Set when the SDL renderer was created with present-vs-sync.
static int vsync_active = 0;
// Save screenshots in PNG format.
// int png_screenshots = 0;
@@ -118,6 +122,11 @@ static int max_scaling_buffer_pixels = 16000000;
// int fullscreen = true;
int fullscreen; //Defined in VIDEO_LoadPrefs to read config from setup.ini
// Borderless window: cover the desktop without decorations (compositor-
// friendly, instant alt-tab). Read from Video/borderless in SETUP.INI.
int borderless = 0;
int txt_fullscreen;
// Aspect ratio correction mode
@@ -208,6 +217,7 @@ void VIDEO_LoadPrefs(void)
fullscreen = INI_GetPreferenceLong("Video", "fullscreen", 0);
aspect_ratio_correct = INI_GetPreferenceLong("Video", "aspect_ratio_correct", 1);
txt_fullscreen = INI_GetPreferenceLong("Video", "txt_fullscreen", 0);
borderless = INI_GetPreferenceLong("Video", "borderless", 0);
}
static bool MouseShouldBeGrabbed()
@@ -386,6 +396,8 @@ static bool ToggleFullScreenKeyShortcut(SDL_Keysym *sym)
sym->scancode == SDL_SCANCODE_KP_ENTER) && (sym->mod & flags) != 0;
}
static void I_GetWindowPosition(int *x, int *y, int w, int h);
static void I_ToggleFullScreen(void)
{
unsigned int flags = 0;
@@ -398,6 +410,38 @@ static void I_ToggleFullScreen(void)
return;
}
if (borderless)
{
// Cycle between the borderless desktop window and a normal
// decorated window.
int x, y, w, h;
fullscreen = !fullscreen;
SDL_SetWindowBordered(screen, (SDL_bool) !fullscreen);
if (fullscreen)
{
SDL_DisplayMode borderless_mode;
SDL_SetWindowPosition(screen, 0, 0);
if (SDL_GetDesktopDisplayMode(video_display, &borderless_mode) == 0)
{
SDL_SetWindowSize(screen, borderless_mode.w, borderless_mode.h);
}
}
else
{
AdjustWindowSize();
I_GetWindowPosition(&x, &y, window_width, window_height);
SDL_SetWindowSize(screen, window_width, window_height);
SDL_SetWindowPosition(screen, x, y);
}
return;
}
fullscreen = !fullscreen;
if (fullscreen)
@@ -740,7 +784,8 @@ void I_FinishUpdate (void)
// When the window is resized (we're not in fullscreen mode),
// save the new window size.
flags = SDL_GetWindowFlags(screen);
if ((flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0)
if ((flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == 0 &&
!(borderless && fullscreen))
{
SDL_GetWindowSize(screen, &window_width, &window_height);
@@ -1233,19 +1278,32 @@ static void SetVideoMode(void)
window_flags |= SDL_WINDOW_FULLSCREEN;
}
}
// Running without window decorations is potentially useful if you're
// playing in three window mode and want to line up three game windows
// next to each other on a single desktop.
// Deliberately not documented because I'm not sure how useful this is yet.
#if 0
if (M_ParmExists("-borderless"))
else if (borderless)
{
// Cover the current desktop without decorations: no mode switch,
// the desktop resolution is used as-is.
SDL_DisplayMode borderless_mode;
if (SDL_GetDesktopDisplayMode(video_display, &borderless_mode) == 0)
{
w = borderless_mode.w;
h = borderless_mode.h;
}
window_flags |= SDL_WINDOW_BORDERLESS;
}
#endif
I_GetWindowPosition(&x, &y, w, h);
if (borderless)
{
// A borderless desktop window sits at the origin.
x = 0;
y = 0;
}
else
{
I_GetWindowPosition(&x, &y, w, h);
}
// Create window and renderer contexts. We set the window title
// later anyway and leave the window position "undefined". If
@@ -1280,10 +1338,11 @@ static void SetVideoMode(void)
video_display, SDL_GetError());
}
// Turn on vsync if we aren't in a -timedemo
if (/*!singletics && */mode.refresh_rate > 0)
// Turn on vsync: the game loop paces simulation on a wall-clock
// accumulator, presentation is throttled by the display.
if (mode.refresh_rate > 0)
{
// renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
}
if (force_software_renderer)
@@ -1324,6 +1383,15 @@ static void SetVideoMode(void)
EXIT_Error("Error creating renderer for screen window: %s",
SDL_GetError());
}
// Remember whether the created renderer actually vsyncs; the game loop
// uses this to decide between vsync pacing and its own delay guard.
{
SDL_RendererInfo rinfo;
vsync_active = (SDL_GetRendererInfo(renderer, &rinfo) == 0 &&
(rinfo.flags & SDL_RENDERER_PRESENTVSYNC) != 0);
}
// Important: Set the "logical size" of the rendering context. At the same
// time this also defines the aspect ratio that is preserved while scaling
@@ -1581,6 +1649,14 @@ void I_SetMousePos(int x, int y)
SDL_WarpMouseInWindow(screen, x, y);
}
/***************************************************************************
I_VsyncActive () - TRUE when the renderer presents with vsync
***************************************************************************/
int I_VsyncActive(void)
{
return vsync_active;
}
void closewindow(void)
{
SDL_DestroyWindow(screen);
+1
View File
@@ -52,4 +52,5 @@ void I_SetGrabMouseCallback(grabmouse_callback_t func);
void VIDEO_LoadPrefs(void);
void closewindow(void);
bool I_GetNeedResize(bool setonlypos);
int I_VsyncActive(void);
void I_Settextmode(bool flag);
-30
View File
@@ -977,36 +977,6 @@ RAP_InitLoadSave(
EXIT_Error("Couldn't find home directory");
}
#if __ANDROID__
for(int i = 0; i < 2; i++)
{
char src[PATH_MAX];
char srclc[PATH_MAX];
char dst[PATH_MAX];
sprintf(src,"FILE%04u.GLB", i);
sprintf(srclc, "file%04u.glb", i);
sprintf(dst, "%sFILE%04u.GLB", cdpath, i);
if (!RAP_CheckFileInPath(src) && !RAP_CheckFileInPath(srclc))
{
SDL_RWops *readsrc = SDL_RWFromFile(src, "rb");
if(readsrc)
{
Sint64 size = SDL_RWsize(readsrc);
char *buffer = (char*)malloc(size);
SDL_RWread(readsrc, buffer, sizeof(char), size);
SDL_RWops *writedst = SDL_RWFromFile(dst, "wb");
if(writedst)
{
SDL_RWwrite(writedst, buffer, sizeof(char), size);
SDL_RWclose(writedst);
}
SDL_RWclose(readsrc);
free(buffer);
}
}
}
#endif //__ANDROID__
return cdpath;
#else
memset(cdpath, 0, sizeof(cdpath));
+15 -4
View File
@@ -595,10 +595,23 @@ OBJS_DisplayStats(
}
else
{
static int dpos_gl = -1;
int new_step = (dpos_gl != gl_cnt);
// The sweep advances once per simulation step, not once per
// rendered frame.
if (new_step)
dpos_gl = gl_cnt;
GFX_VLine(dpos + 110, MAP_BOTTOM + 8, 3, 68);
GFX_VLine(209 - dpos, MAP_BOTTOM + 8, 3, 68);
dpos++;
dpos %= 50;
if (new_step)
{
dpos++;
dpos %= 50;
}
}
}
@@ -692,8 +705,6 @@ OBJS_Add(
if (type >= S_LAST_OBJECT)
return OBJ_ERROR;
g_oldsuper = -1;
g_oldshield = -1;
lib = &obj_lib[type];
+172 -122
View File
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include "SDL.h"
#include "common.h"
#include "glbapi.h"
@@ -30,7 +31,6 @@
#include "flame.h"
#include "input.h"
#include "joyapi.h"
#include "i_lastscr.h"
#include "fileids.h"
#include "entypes.h"
@@ -109,8 +109,10 @@ int player_cx = PLAYERINITX;
int player_cy = PLAYERINITY;
int playerbasepic = 3;
int startfadeflag;
int g_oldsuper = -1;
int g_oldshield = -1;
// Shield level latched by RAP_ThinkStats at the end of each simulation step;
// used there to detect fresh damage. This is NOT a display dirty flag --
// RAP_DisplayStats redraws the shield bars unconditionally every frame.
static int g_oldshield = -1;
int startendwave = -1;
int gl_cnt;
int g_flash = 0;
@@ -119,6 +121,16 @@ int end_wave;
int playerpic = 4;
int g_mapleft;
// Interpolated player center, recomputed once per rendered frame and
// consumed by draw code that cannot reach the Do_Game() locals.
int g_ipcx, g_ipcy;
static int pp_x, pp_y, pp_cx, pp_cy;
// Simulation tick: 3/70 s written in units of 1/70000 s.
#define RAP_SIM_STEP 3000
int fadecnt;
#define ROTPAL_START 240
@@ -209,8 +221,6 @@ ShutDown(
int errcode
)
{
char* mem;
if (!errcode && !godmode)
WIN_Order();
@@ -220,13 +230,7 @@ ShutDown(
//PTR_End();
//KBD_End();
if (reg_flag)
mem = GLB_GetItem(FILE002_LASTSCR2_TXT); //Get ANSI Screen Fullversion from GLB to char*
else
mem = GLB_GetItem(FILE001_LASTSCR1_TXT); //Get ANSI Screen Shareware from GLB to char*
closewindow(); //Close Main Window
I_LASTSCR(mem); //Call to display ANSI Screen
GLB_FreeAll();
IPT_CloJoy(); //Close Joystick
SWD_End();
@@ -497,38 +501,28 @@ RAP_DisplayShieldLevel(
}
/***************************************************************************
RAP_DisplayStats() -
RAP_ThinkStats () - Simulation-side half of the status logic: death
sequence, wave-exit control and low-shield warnings.
Split from RAP_DisplayStats so state changes stay
locked to simulation steps while drawing runs at the
presentation rate.
***************************************************************************/
static int stats_damage = -1;
static int stats_blinkflag = 1;
void
RAP_DisplayStats(
RAP_ThinkStats(
void
)
{
char temp[24];
int super, shield, loop, x, y;
char* pic;
GFX_PIC *h;
static int damage = -1;
static int blinkflag = 1;
// == DISPLAY SUPER SHIELD ========================
super = OBJS_GetAmt(S_SUPER_SHIELD);
if (g_oldsuper != super)
{
RAP_DisplayShieldLevel(MAP_LEFT - 8, super);
g_oldsuper = super;
}
// == DISPLAY NORM SHIELD ========================
shield = OBJS_GetAmt(S_ENERGY);
if (g_oldshield != shield)
{
RAP_DisplayShieldLevel(MAP_RIGHT + 4, shield);
}
if (shield <= 0 && !godmode)
{
// BLOW UP SHIP IF ! IN GOD MODE ===================
// == BLOW UP SHIP IF ! IN GOD MODE ===================
ANIMS_StartAnim(A_MED_AIR_EXPLO, playerx + (wrand()%32), playery + (wrand()%32));
ANIMS_StartAnim(A_SMALL_AIR_EXPLO, playerx + (wrand()%32), playery + (wrand()%32));
@@ -565,7 +559,7 @@ RAP_DisplayStats(
}
}
// IF END OF WAVE FLY SHIP OFF SCREEN ===================
// == IF END OF WAVE FLY SHIP OFF SCREEN ===================
if (startendwave != -1 && shield > 0)
{
@@ -592,17 +586,17 @@ RAP_DisplayStats(
{
if (!(gl_cnt % 8))
{
blinkflag ^= 1;
stats_blinkflag ^= 1;
if (blinkflag)
if (stats_blinkflag)
{
if (damage)
if (stats_damage)
{
damage--;
stats_damage--;
if ((haptic) && (control == 2))
{
IPT_CalJoyRumbleHigh();
IPT_CalJoyRumbleHigh();
}
}
}
@@ -613,30 +607,57 @@ RAP_DisplayStats(
if (OBJS_LoseObj())
{
SND_Patch(FX_CRASH, 127);
damage = 2;
stats_damage = 2;
}
}
if (blinkflag)
{
if (damage)
{
pic = GLB_GetItem(FILE111_WEPDEST_PIC);
h = (GFX_PIC*)pic;
GFX_PutSprite(pic, (320 - LE_LONG(h->width)) >> 1, MAP_BOTTOM - 9);
}
if (startendwave == -1)
SND_Patch(FX_WARNING, 127);
pic = GLB_GetItem(FILE110_SHLDLOW_PIC);
h = (GFX_PIC*)pic;
GFX_PutSprite(pic, (320 - LE_LONG(h->width)) >> 1, MAP_BOTTOM);
}
if (stats_blinkflag && startendwave == -1)
SND_Patch(FX_WARNING, 127);
}
g_oldshield = shield;
}
/***************************************************************************
RAP_DisplayStats() -
***************************************************************************/
void
RAP_DisplayStats(
void
)
{
char temp[24];
int shield, loop, x, y;
char* pic;
GFX_PIC *h;
// == DISPLAY SUPER SHIELD ========================
// Both bars are redrawn on every rendered frame. They were once cached
// behind g_oldsuper/g_oldshield change checks, but RAP_ThinkStats now
// re-latches g_oldshield once per simulation step -- before this draw
// code ever runs -- so the checks could never fire again and the bars
// froze. Drawing is idempotent and cheap; the bars write straight into
// displayscreen outside the blitted map area, so this also restores
// them after menus or fades clear the sides.
RAP_DisplayShieldLevel(MAP_LEFT - 8, OBJS_GetAmt(S_SUPER_SHIELD));
// == DISPLAY NORM SHIELD ========================
shield = OBJS_GetAmt(S_ENERGY);
RAP_DisplayShieldLevel(MAP_RIGHT + 4, shield);
if (shield <= SHIELD_LOW && !godmode && stats_blinkflag)
{
if (stats_damage)
{
pic = GLB_GetItem(FILE111_WEPDEST_PIC);
h = (GFX_PIC*)pic;
GFX_PutSprite(pic, (320 - LE_LONG(h->width)) >> 1, MAP_BOTTOM - 9);
}
pic = GLB_GetItem(FILE110_SHLDLOW_PIC);
h = (GFX_PIC*)pic;
GFX_PutSprite(pic, (320 - LE_LONG(h->width)) >> 1, MAP_BOTTOM);
}
OBJS_DisplayStats();
sprintf(temp, "%08u", plr.score);
@@ -809,7 +830,7 @@ Do_Game(
void
)
{
int b2_flag, b3_flag, init_flag, rval, start_score, local_cnt;
int b2_flag, b3_flag, init_flag, rval, start_score;
b2_flag = 0;
b3_flag = 0;
init_flag = 1;
@@ -852,11 +873,9 @@ Do_Game(
memset(displaybuffer, 0, 64000);
memset(displayscreen, 0, 64000);
local_cnt = GFX_GetFrameCount();
Uint32 sim_next = SDL_GetTicks() * 70; // due time of next sim step
g_flash = 0;
g_oldsuper = -1;
g_oldshield = -1;
startendwave = -1;
if (demo_flag == DEMO_RECORD)
@@ -871,6 +890,11 @@ Do_Game(
do
{
num_shadows = num_gshadows = 0;
pp_x = playerx;
pp_y = playery;
pp_cx = player_cx;
pp_cy = player_cy;
#ifdef __ANDROID__
if (!I_GetNeedResize(true))
@@ -886,8 +910,6 @@ Do_Game(
HELP_Win("OVERVW06_TXT");
memset(displayscreen, 0, 64000);
IPT_Start();
g_oldsuper = -1;
g_oldshield = -1;
RAP_ClearSides();
RAP_DisplayStats();
SWD_SetClearFlag(1);
@@ -908,8 +930,6 @@ Do_Game(
SWD_SetClearFlag(0);
RAP_ClearSides();
WIN_Pause();
g_oldsuper = -1;
g_oldshield = -1;
RAP_ClearSides();
RAP_DisplayStats();
SWD_SetClearFlag(1);
@@ -1046,6 +1066,8 @@ Do_Game(
gl_cnt++;
TILE_Scroll();
TILE_Think();
ENEMY_Think();
ESHOT_Think();
@@ -1057,27 +1079,10 @@ Do_Game(
if (draw_player)
SHADOW_Add(curship[playerpic + g_flash], playerx, playery);
TILE_Display();
SHADOW_DisplayGround();
ENEMY_DisplayGround();
SHADOW_DisplaySky();
ANIMS_DisplayGround();
SHADOW_Snapshot();
ENEMY_DisplaySky();
SHOTS_Display();
BONUS_Display();
ANIMS_DisplaySky();
if (draw_player)
{
FLAME_Down(player_cx - o_engine[playerpic] - 3, player_cy + 15, 4, gl_cnt % 2);
FLAME_Down(player_cx + o_engine[playerpic] - 2, player_cy + 15, 4, gl_cnt % 2);
GFX_PutSprite((char*)GLB_GetItem(curship[playerpic + g_flash]), playerx, playery);
g_flash = 0;
}
ANIMS_DisplayHigh();
ESHOT_Display();
// == FADE / PALETTE SIMULATION =====================================
// (advanced once per simulation step; was interleaved with drawing)
if (fadeflag)
{
@@ -1087,8 +1092,6 @@ Do_Game(
g_mapleft = MAP_LEFT;
GFX_SetPalette(gpal, 0);
fadeflag = 0;
g_oldsuper = -1;
g_oldshield = -1;
}
else
{
@@ -1106,18 +1109,7 @@ Do_Game(
RAP_PaletteStuff();
}
RAP_DisplayStats();
while (GFX_GetFrameCount() - local_cnt < 3)
{
}
local_cnt = GFX_GetFrameCount();
if (fadeflag)
TILE_ShakeScreen();
else
TILE_DisplayScreen();
RAP_ThinkStats();
if (startfadeflag)
{
@@ -1147,6 +1139,85 @@ Do_Game(
GFX_FadeIn(gpal, 64);
}
// == PRESENTATION ==================================================
// Redraw interpolated frames until the next simulation step is due.
// When running behind (a blocking menu ate wall time), skip renders
// and let the simulation catch up -- the old tick-wait loop did the
// same because the frame counter kept counting during menus.
if (SDL_GetTicks() * 70 - sim_next >= RAP_SIM_STEP)
{
sim_next += RAP_SIM_STEP;
}
else
{
for (;;)
{
Uint32 now = SDL_GetTicks() * 70;
Uint32 pend;
if (now - sim_next >= RAP_SIM_STEP)
break;
pend = sim_next - now; // time until the next sim step
GFX_SetInterp(RAP_SIM_STEP - pend, RAP_SIM_STEP);
I_GetEvent();
g_ipcx = GFX_InterpCoord(player_cx, pp_cx);
g_ipcy = GFX_InterpCoord(player_cy, pp_cy);
TILE_Display();
SHADOW_DisplayGround();
ENEMY_DisplayGround();
SHADOW_DisplaySky();
ANIMS_DisplayGround();
ENEMY_DisplaySky();
SHOTS_Display();
BONUS_Display();
ANIMS_DisplaySky();
if (draw_player)
{
int ipx = GFX_InterpCoord(playerx, pp_x);
int ipy = GFX_InterpCoord(playery, pp_y);
FLAME_Down(g_ipcx - o_engine[playerpic] - 3, g_ipcy + 15, 4, gl_cnt % 2);
FLAME_Down(g_ipcx + o_engine[playerpic] - 2, g_ipcy + 15, 4, gl_cnt % 2);
GFX_PutSprite((char*)GLB_GetItem(curship[playerpic + g_flash]), ipx, ipy);
}
// Above-player layer (most air explosions register as
// HIGH_AIR); upstream draws it between the player and
// enemy shots -- dropping it made dying ships despawn
// without their explosion anims.
ANIMS_DisplayHigh();
ESHOT_Display();
RAP_DisplayStats();
if (fadeflag)
TILE_ShakeScreen();
else
TILE_DisplayScreen();
if (!I_VsyncActive())
{
now = SDL_GetTicks() * 70;
if (sim_next - now > 280)
SDL_Delay(1);
}
}
sim_next += RAP_SIM_STEP;
}
// Muzzle-flash ship pic lasts exactly one simulation step, matching
// the original tick loop. Clearing it per rendered frame (inside the
// interpolation loop) made the flash vanish at display refresh rates.
g_flash = 0;
if (KBD_Key(SC_X) && KBD_Key(SC_ALT))
{
RAP_ClearSides();
@@ -1154,8 +1225,6 @@ Do_Game(
IPT_End();
WIN_AskExit();
IPT_Start();
g_oldsuper = -1;
g_oldshield = -1;
RAP_ClearSides();
RAP_DisplayStats();
SWD_SetClearFlag(1);
@@ -1196,8 +1265,6 @@ Do_Game(
#endif //__ANDROID__
IPT_Start();
g_oldsuper = -1;
g_oldshield = -1;
RAP_ClearSides();
RAP_DisplayStats();
SWD_SetClearFlag(1);
@@ -1320,27 +1387,13 @@ main(
printf("GOD mode enabled\n");
cur_diff = 0;
if (!access("FILE0001.GLB", 0) ||
!access("file0001.glb", 0) ||
RAP_CheckFileInPath("FILE0001.GLB") ||
RAP_CheckFileInPath("file0001.glb"))
if (GLB_SlotItems(1) > 0)
gameflag[0] = 1;
if (!access("FILE0002.GLB", 0) ||
!access("file0002.glb", 0) ||
RAP_CheckFileInPath("FILE0002.GLB") ||
RAP_CheckFileInPath("file0002.glb"))
if (GLB_SlotItems(2) > 0)
gameflag[1] = 1;
if ((!access("FILE0003.GLB", 0) && !access("FILE0004.GLB", 0)) ||
(!access("file0003.glb", 0) && !access("file0004.glb", 0)) ||
(!access("FILE0003.GLB", 0) && !access("file0004.glb", 0)) ||
(!access("file0003.glb", 0) && !access("FILE0004.GLB", 0)) ||
(RAP_CheckFileInPath("FILE0003.GLB") && RAP_CheckFileInPath("FILE0004.GLB")) ||
(RAP_CheckFileInPath("file0003.glb") && RAP_CheckFileInPath("file0004.glb")) ||
(RAP_CheckFileInPath("FILE0003.GLB") && RAP_CheckFileInPath("file0004.glb")) ||
(RAP_CheckFileInPath("file0003.glb") && RAP_CheckFileInPath("FILE0004.GLB")))
if (GLB_SlotItems(3) > 0 && GLB_SlotItems(4) > 0)
{
gameflag[2] = 1;
gameflag[3] = 1;
@@ -1356,10 +1409,7 @@ main(
if (gameflag[loop])
numfiles++;
}
if ((access("FILE0000.GLB", 0) && !RAP_CheckFileInPath("FILE0000.GLB")) &&
(access("file0000.glb", 0) && !RAP_CheckFileInPath("file0000.glb")) ||
!numfiles)
if (GLB_SlotItems(0) == 0 || !numfiles)
{
printf("All game data files NOT FOUND cannot proceed !!\n");
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
+1 -1
View File
@@ -43,8 +43,8 @@ extern int player_cx, player_cy;
extern int startfadeflag;
extern int startendwave;
extern int gl_cnt;
extern int g_oldsuper, g_oldshield;
extern int playerx, playery;
extern int g_ipcx, g_ipcy;
extern char gdmodestr[];
extern int playerbasepic;
+36 -16
View File
@@ -23,6 +23,26 @@ SHADOW shads[MAX_SHADOWS];
SHADOW gshads[MAX_GSHADOWS];
int num_shadows, num_gshadows;
static SHADOW prev_shads[MAX_SHADOWS];
static SHADOW prev_gshads[MAX_GSHADOWS];
static int prev_num_shadows, prev_num_gshadows;
/***************************************************************************
SHADOW_Snapshot () - Latches this simulation step's shadows as previous
positions for interpolated display
***************************************************************************/
void
SHADOW_Snapshot(
void
)
{
memcpy(prev_shads, shads, sizeof(shads));
memcpy(prev_gshads, gshads, sizeof(gshads));
prev_num_shadows = num_shadows;
prev_num_gshadows = num_gshadows;
}
#define MAXZ 1280;
/***************************************************************************
@@ -194,20 +214,20 @@ SHADOW_DisplaySky(
)
{
char *pic;
SHADOW *cur;
cur = shads;
int i;
int ix, iy;
if (opt_detail < 1)
return;
while (--num_shadows != -1)
for (i = 0; i < num_shadows; i++)
{
pic = GLB_GetItem(cur->item);
SHADOW_Draw(pic, cur->x, cur->y);
cur++;
ix = (i < prev_num_shadows) ? GFX_InterpCoord(shads[i].x, prev_shads[i].x) : shads[i].x;
iy = (i < prev_num_shadows) ? GFX_InterpCoord(shads[i].y, prev_shads[i].y) : shads[i].y;
pic = GLB_GetItem(shads[i].item);
SHADOW_Draw(pic, ix, iy);
}
num_shadows = 0;
}
/***************************************************************************
@@ -219,18 +239,18 @@ SHADOW_DisplayGround(
)
{
char *pic;
SHADOW *cur;
cur = gshads;
int i;
int ix, iy;
if (opt_detail < 1)
return;
while (--num_gshadows != -1)
for (i = 0; i < num_gshadows; i++)
{
pic = GLB_GetItem(cur->item);
GFX_ShadeShape(DARK, (char*)pic, cur->x, cur->y);
cur++;
ix = (i < prev_num_gshadows) ? GFX_InterpCoord(gshads[i].x, prev_gshads[i].x) : gshads[i].x;
iy = (i < prev_num_gshadows) ? GFX_InterpCoord(gshads[i].y, prev_gshads[i].y) : gshads[i].y;
pic = GLB_GetItem(gshads[i].item);
GFX_ShadeShape(DARK, (char*)pic, ix, iy);
}
num_gshadows = 0;
}
+1
View File
@@ -8,4 +8,5 @@ void SHADOW_MakeShades(void);
void SHADOW_GAdd(int item, int x, int y);
void SHADOW_Add(int item, int x, int y);
void SHADOW_DisplayGround();
void SHADOW_Snapshot(void);
void SHADOW_DisplaySky();
+36 -14
View File
@@ -779,6 +779,7 @@ SHOTS_PlayerShoot(
cur->speed = lib->speed;
cur->x = player_cx;
cur->y = player_cy;
cur->age = 0;
cur->move.x = (wrand() % enemy->width) + enemy->move.x - 1;
cur->move.y = (wrand() % enemy->height) + enemy->move.y - 1;
cur->move.x2 = player_cx;
@@ -1019,7 +1020,23 @@ SHOTS_Think(
for (shot = first_shots.next; &last_shots != shot; shot = shot->next)
{
lib = shot->lib;
// S_LINE tracers (laser turret) live exactly one simulation step:
// created during this iteration's input phase, they get ONE Think
// pass (position + damage) and are drawn by every render of this
// step, then purged here at the top of the NEXT Think. Upstream
// removed them inside the display pass, which no longer owns state.
// doneflag must NOT be used: it is hit/retire game state, and the
// turret's retire path never frees the shot, so reusing it leaked
// one pool slot per fire until SHOTS_Get() serviced no weapon.
if (lib->beam == S_LINE && ++shot->age > 1)
{
shot = SHOTS_Remove(shot);
continue;
}
shot->px = shot->x;
shot->py = shot->y;
switch (lib->beam)
{
default:
@@ -1046,6 +1063,8 @@ SHOTS_Think(
shot->pic = lib->pic[shot->curframe];
shot->x = shot->move.x - lib->hlx;
shot->y = shot->move.y;
shot->cnt++;
shot->cnt = shot->cnt % 4;
for (enemy = first_enemy.next; &last_enemy != enemy; enemy = enemy->next)
{
@@ -1257,12 +1276,15 @@ SHOTS_Display(
void
)
{
int loop, x, y;
int loop, x, y, ix, iy;
SHOTS *shot;
GFX_PIC *h;
for (shot = first_shots.next; shot != &last_shots; shot = shot->next)
{
ix = GFX_InterpCoord(shot->x, shot->px);
iy = GFX_InterpCoord(shot->y, shot->py);
switch (shot->lib->beam)
{
default:
@@ -1270,37 +1292,37 @@ SHOTS_Display(
break;
case S_SHOOT:
GFX_PutSprite(shot->pic, shot->x, shot->y);
GFX_PutSprite(shot->pic, ix, iy);
break;
case S_LINE:
GFX_Line(player_cx + 1, player_cy, shot->move.x, shot->move.y, 69);
GFX_Line(player_cx - 1, player_cy, shot->move.x, shot->move.y, 69);
GFX_Line(player_cx, player_cy, shot->move.x, shot->move.y, 64);
shot = SHOTS_Remove(shot);
// Exists only during its birth step (purged by SHOTS_Think),
// so every rendered frame of that step draws the beam -- on a
// hitting tick too, which the old doneflag guard hid.
GFX_Line(g_ipcx + 1, g_ipcy, shot->move.x, shot->move.y, 69);
GFX_Line(g_ipcx - 1, g_ipcy, shot->move.x, shot->move.y, 69);
GFX_Line(g_ipcx, g_ipcy, shot->move.x, shot->move.y, 64);
break;
case S_BEAM:
for (loop = shot->move.y2; loop < shot->y; loop += 3)
for (loop = shot->move.y2; loop < iy; loop += 3)
{
GFX_PutSprite(shot->pic, shot->x, loop);
GFX_PutSprite(shot->pic, ix, loop);
}
if (shot->lib->type == S_DEATH_RAY)
GFX_PutSprite(detpow[shot->cnt], shot->x - 4, shot->y);
GFX_PutSprite(detpow[shot->cnt], ix - 4, iy);
else
GFX_PutSprite(laspow[shot->cnt], shot->x, shot->y);
GFX_PutSprite(laspow[shot->cnt], ix, iy);
h = (GFX_PIC*)lashit[shot->cnt];
x = shot->x - (LE_LONG(h->width) >> 2);
x = ix - (LE_LONG(h->width) >> 2);
y = shot->move.y2 - 8;
if (y > 0)
GFX_PutSprite((char*)h, x, y);
shot->cnt++;
shot->cnt = shot->cnt % 4;
break;
}
}
+3
View File
@@ -56,6 +56,8 @@ typedef struct SHOTS_S
char *pic; // pointer to cur frame pic
int x; // cur shot center x
int y; // cur shot center y
int px; // prev sim x (interp)
int py; // prev sim y (interp)
MOVEOBJ move; // MOVE stuff
int speed; // cur speed
int curframe; // current anim frame
@@ -65,6 +67,7 @@ typedef struct SHOTS_S
int starty; // PLAYER Y OFFSET;
SHOT_LIB *lib;
int cnt;
int age; // sim steps survived (S_LINE purge in SHOTS_Think)
}SHOTS;
extern char *lashit[4];
-1
View File
@@ -265,7 +265,6 @@ STORE_Enter(
GFX_DisplayUpdate();
GFX_FadeIn(palette, 16);
SWD_SetFieldPtr(window, STOR_VEXIT);
PTR_DrawCursor(1);
OBJS_GetNum();
-63
View File
@@ -1877,69 +1877,6 @@ SWD_ShowAllWindows(
return 1;
}
/***************************************************************************
SWD_SetWindowPtr() - Sets Pointer to center of active field
***************************************************************************/
void
SWD_SetWindowPtr(
int handle // INPUT : number/handle of window
)
{
SWIN *curwin;
SFIELD *curfld;
curwin = g_wins[handle].win;
if (!ptractive || handle == -1)
return;
if (active_field == -1 || !LE_LONG(curwin->numflds))
{
if (!g_wins[handle].flag || curwin == NULL)
return;
PTR_SetPos(LE_LONG(curwin->x) + (LE_LONG(curwin->lx)>>1), LE_LONG(curwin->y) + (LE_LONG(curwin->ly)>>1));
}
else
{
curfld = (SFIELD*)((char*)curwin + LE_LONG(curwin->fldofs));
curfld += active_field;
PTR_SetPos(LE_LONG(curfld->x) + (LE_LONG(curfld->lx)>>1), LE_LONG(curfld->y) + (LE_LONG(curfld->ly)>>1));
}
}
/***************************************************************************
SWD_SetFieldPtr () - Sets Pointer on a field
***************************************************************************/
void
SWD_SetFieldPtr(
int handle, // INPUT : number/handle of window
int field // INPUT : field
)
{
SWIN *curwin;
SFIELD *curfld;
curwin = g_wins[handle].win;
if (!ptractive || handle == -1)
return;
if (field == -1 || !LE_LONG(curwin->numflds))
{
if (!g_wins[handle].flag || curwin == NULL)
return;
PTR_SetPos(LE_LONG(curwin->x) + (LE_LONG(curwin->lx)>>1), LE_LONG(curwin->y) + (LE_LONG(curwin->ly)>>1));
}
else
{
curfld = (SFIELD*)((char*)curwin + LE_LONG(curwin->fldofs));
curfld += field;
PTR_SetPos(LE_LONG(curfld->x) + (LE_LONG(curfld->lx)>>1), LE_LONG(curfld->y) + (LE_LONG(curfld->ly)>>1));
}
}
/***************************************************************************
SWD_SetActiveWindow() - Sets the current working window
***************************************************************************/
-2
View File
@@ -222,7 +222,6 @@ void SWD_Dialog(SWD_DLG *swd_dlg);
SWIN* SWD_ReformatFieldData(SWIN *header, int handle);
int SWD_InitMasterWindow(int handle);
int SWD_ShowAllWindows(void);
void SWD_SetWindowPtr(int handle);
void SWD_SetFieldSelect(int handle, int field_id, int opt);
void SWD_SetFieldItem(int handle, int field_id, int item);
int SWD_SetFieldText(int handle, int field_id, const char *in_text);
@@ -231,7 +230,6 @@ int SWD_InitWindow(int handle);
void SWD_SetActiveField(int handle, int field_id);
int SWD_GetFieldXYL(int handle, int field_id, int* x, int* y, int* lx, int* ly);
void SWD_SetWinDrawFunc(int handle, void (*infunc)(SWD_DLG*));
void SWD_SetFieldPtr(int handle, int field);
int SWD_GetFieldText(int handle, int field_id, char *out_text);
int SWD_GetFieldItem(int handle, int field_id);
void SWD_SetClearFlag(int inflag);
+26 -1
View File
@@ -46,6 +46,13 @@ int startflat[4];
int tilepos;
int tileyoff;
// Unwrapped scroll counters for interpolation. The raw tileyoff wraps by
// MAP_BLOCKSIZE while the on-screen tile grid stays positionally continuous
// (the wrap and the row shift cancel), so the visual offset must be derived
// from a counter that never wraps.
static int vscroll, vscroll_prev;
TILESPOT tspots[MAX_STILES];
TILESPOT *lastspot;
int spark_delay;
@@ -423,20 +430,35 @@ TILE_Display(
{
char *pic;
TILESPOT *ts;
int oy;
oy = GFX_InterpCoord(vscroll, vscroll_prev) - vscroll;
ts = tspots;
do
{
pic = GLB_GetItem(ts->item);
pic += 20;
TILE_Put(pic, ts->x, ts->y);
TILE_Put(pic, ts->x, ts->y + oy);
if (ts == lastspot)
break;
ts++;
} while (1);
}
/***************************************************************************
TILE_Scroll () - Advances the map scroll one simulation step
(moved out of TILE_Display for decoupled rendering)
***************************************************************************/
void
TILE_Scroll(
void
)
{
vscroll_prev = vscroll;
tileyoff++;
@@ -459,6 +481,9 @@ TILE_Display(
last_tile = 1;
}
}
if (scroll_flag)
vscroll++;
}
/***************************************************************************
+1
View File
@@ -28,6 +28,7 @@ typedef struct TDELAY_S
void TILE_Init(void);
void TILE_Think(void);
void TILE_Display(void);
void TILE_Scroll(void);
int TILE_IsHit(int damage, int x, int y);
int TILE_Bomb(int damage, int x, int y);
void TILE_Explode(TILESPOT *ts, int delay);
-19
View File
@@ -212,7 +212,6 @@ WIN_Opts(
opt_window = SWD_InitWindow(FILE13f_OPTS_SWD);
SWD_SetWindowPtr(opt_window);
SWD_SetFieldText(opt_window, OPTS_DETAIL, detail[curd]);
SWD_SetWinDrawFunc(opt_window, WIN_OptDraw);
@@ -564,7 +563,6 @@ WIN_AskBool(
int rval;
int dchold;
int ask_window;
int px, py, lx, ly;
SWD_DLG dlg;
rval = 0;
@@ -583,9 +581,6 @@ WIN_AskBool(
PTR_DrawCursor(1);
SWD_GetFieldXYL(ask_window, ASK_YES, &px, &py, &lx, &ly);
PTR_SetPos(px + (lx >> 1), py + (ly >> 1));
SWD_SetActiveField(ask_window, ASK_YES);
while (1)
@@ -698,7 +693,6 @@ WIN_AskDiff(
{
SWD_DLG dlg;
int rval, ask_window;
int px, py, lx, ly;
rval = -1;
@@ -709,9 +703,6 @@ WIN_AskDiff(
SWD_ShowAllWindows();
GFX_DisplayUpdate();
SWD_GetFieldXYL(ask_window, OKREG_MED, &px, &py, &lx, &ly);
PTR_SetPos(px + (lx >> 1), py + (ly >> 1));
while (1)
{
SWD_Dialog(&dlg);
@@ -798,7 +789,6 @@ WIN_Register(
GFX_FadeIn(palette, 16);
SWD_SetFieldPtr(window, REG_VIEWID);
PTR_DrawCursor(1);
#ifdef __ANDROID__
@@ -1086,7 +1076,6 @@ WIN_Hangar(
char temp[44];
SWD_DLG dlg;
int opt, oldopt, pos, kflag, local_cnt, pic_cnt, window;
int x, y, lx, ly;
int poslookup[4] = {
HANG_MISSION,
HANG_SUPPLIES,
@@ -1143,7 +1132,6 @@ WIN_Hangar(
hangto = HANGTOMISSION;
SWD_SetWindowPtr(window);
PTR_DrawCursor(1);
while (1)
@@ -1277,8 +1265,6 @@ WIN_Hangar(
if (opt != oldopt)
{
oldopt = opt;
SWD_GetFieldXYL(window, opt, &x, &y, &lx, &ly);
PTR_SetPos(x + (lx>>1), y + (ly>>1));
oldopt = -1;
dlg.sfield = opt;
dlg.viewactive = 1;
@@ -1465,7 +1451,6 @@ WIN_ShipComp(
SWD_DLG dlg;
int rval, secret1, secret2, secret3, secret, cz1, cz2;
int window;
int px, py, lx, ly;
rval = 1;
secret1 = 0;
@@ -1495,8 +1480,6 @@ WIN_ShipComp(
GLB_LockItem(FILE12a_LIGHTON_PIC);
GLB_LockItem(FILE12b_LIGHTOFF_PIC);
SWD_GetFieldXYL(window, COMP_AUTO, &px, &py, &lx, &ly);
PTR_SetPos(px + (lx >> 1), py + (ly >> 1));
SWD_SetActiveField(window, COMP_AUTO);
SWD_SetFieldItem(window, COMP_LITE1, FILE12b_LIGHTOFF_PIC);
@@ -1520,7 +1503,6 @@ WIN_ShipComp(
GFX_FadeIn(palette, 16);
SWD_SetWindowPtr(window);
PTR_DrawCursor(1);
while (1)
@@ -2105,7 +2087,6 @@ WIN_MainMenu(
SND_CacheIFX();
SWD_SetWindowPtr(window);
PTR_DrawCursor(1);
ltable[0] = 0;