mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-04-21 06:11:03 +00:00
Merge remote-tracking branch 'public/master'
This commit is contained in:
commit
c1937e459b
293 changed files with 5241 additions and 2041 deletions
|
@ -51,7 +51,7 @@ enum
|
|||
MAXSTATUS = 1024,
|
||||
// Maximum number of component tiles in a multi-psky:
|
||||
MAXPSKYTILES = 16,
|
||||
MAXSPRITESONSCREEN = 2560,
|
||||
MAXSPRITESONSCREEN = MAXSPRITES >> 2,
|
||||
MAXUNIQHUDID = 256, //Extra slots so HUD models can store animation state without messing game sprites
|
||||
|
||||
TSPR_TEMP = 99,
|
||||
|
|
|
@ -124,7 +124,7 @@ static void Shape2D_Clear(DShape2D* self, int which)
|
|||
if (which & C_Verts) self->mVertices.Clear();
|
||||
if (which & C_Coords) self->mCoords.Clear();
|
||||
if (which & C_Indices) self->mIndices.Clear();
|
||||
self->needsVertexUpload = true;
|
||||
self->bufferInfo->needsVertexUpload = true;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear)
|
||||
|
@ -138,7 +138,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, Clear, Shape2D_Clear)
|
|||
static void Shape2D_PushVertex(DShape2D* self, double x, double y)
|
||||
{
|
||||
self->mVertices.Push(DVector2(x, y));
|
||||
self->needsVertexUpload = true;
|
||||
self->bufferInfo->needsVertexUpload = true;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex)
|
||||
|
@ -153,7 +153,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushVertex, Shape2D_PushVertex)
|
|||
static void Shape2D_PushCoord(DShape2D* self, double u, double v)
|
||||
{
|
||||
self->mCoords.Push(DVector2(u, v));
|
||||
self->needsVertexUpload = true;
|
||||
self->bufferInfo->needsVertexUpload = true;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushCoord, Shape2D_PushCoord)
|
||||
|
@ -170,7 +170,7 @@ static void Shape2D_PushTriangle(DShape2D* self, int a, int b, int c)
|
|||
self->mIndices.Push(a);
|
||||
self->mIndices.Push(b);
|
||||
self->mIndices.Push(c);
|
||||
self->needsVertexUpload = true;
|
||||
self->bufferInfo->needsVertexUpload = true;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DShape2D, PushTriangle, Shape2D_PushTriangle)
|
||||
|
@ -528,13 +528,15 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms)
|
|||
offset = osave;
|
||||
}
|
||||
|
||||
static TArray<RefCountedPtr<DShape2DBufferInfo>> buffersToDestroy;
|
||||
|
||||
void DShape2D::OnDestroy() {
|
||||
if (lastParms) delete lastParms;
|
||||
lastParms = nullptr;
|
||||
mIndices.Reset();
|
||||
mVertices.Reset();
|
||||
mCoords.Reset();
|
||||
buffers.Reset();
|
||||
buffersToDestroy.Push(std::move(bufferInfo));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -567,11 +569,11 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
|
|||
shape->lastParms = new DrawParms(parms);
|
||||
}
|
||||
else if (shape->lastParms->vertexColorChange(parms)) {
|
||||
shape->needsVertexUpload = true;
|
||||
if (!shape->uploadedOnce) {
|
||||
shape->bufIndex = -1;
|
||||
shape->buffers.Clear();
|
||||
shape->lastCommand = -1;
|
||||
shape->bufferInfo->needsVertexUpload = true;
|
||||
if (!shape->bufferInfo->uploadedOnce) {
|
||||
shape->bufferInfo->bufIndex = -1;
|
||||
shape->bufferInfo->buffers.Clear();
|
||||
shape->bufferInfo->lastCommand = -1;
|
||||
}
|
||||
delete shape->lastParms;
|
||||
shape->lastParms = new DrawParms(parms);
|
||||
|
@ -583,7 +585,7 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
|
|||
auto osave = offset;
|
||||
if (parms.nooffset) offset = { 0,0 };
|
||||
|
||||
if (shape->needsVertexUpload)
|
||||
if (shape->bufferInfo->needsVertexUpload)
|
||||
{
|
||||
shape->minx = 16383;
|
||||
shape->miny = 16383;
|
||||
|
@ -622,15 +624,15 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
|
|||
dg.transform = shape->transform;
|
||||
dg.transform.Cells[0][2] += offset.X;
|
||||
dg.transform.Cells[1][2] += offset.Y;
|
||||
dg.shape2D = shape;
|
||||
dg.shape2DBufInfo = shape->bufferInfo;
|
||||
dg.shape2DIndexCount = shape->mIndices.Size();
|
||||
if (shape->needsVertexUpload)
|
||||
if (shape->bufferInfo->needsVertexUpload)
|
||||
{
|
||||
shape->bufIndex += 1;
|
||||
shape->bufferInfo->bufIndex += 1;
|
||||
|
||||
shape->buffers.Reserve(1);
|
||||
shape->bufferInfo->buffers.Reserve(1);
|
||||
|
||||
auto buf = &shape->buffers[shape->bufIndex];
|
||||
auto buf = &shape->bufferInfo->buffers[shape->bufferInfo->bufIndex];
|
||||
|
||||
auto verts = TArray<TwoDVertex>(dg.mVertCount, true);
|
||||
for ( int i=0; i<dg.mVertCount; i++ )
|
||||
|
@ -649,12 +651,12 @@ void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
|
|||
}
|
||||
|
||||
buf->UploadData(&verts[0], dg.mVertCount, &shape->mIndices[0], shape->mIndices.Size());
|
||||
shape->needsVertexUpload = false;
|
||||
shape->uploadedOnce = true;
|
||||
shape->bufferInfo->needsVertexUpload = false;
|
||||
shape->bufferInfo->uploadedOnce = true;
|
||||
}
|
||||
dg.shape2DBufIndex = shape->bufIndex;
|
||||
shape->lastCommand += 1;
|
||||
dg.shape2DCommandCounter = shape->lastCommand;
|
||||
dg.shape2DBufIndex = shape->bufferInfo->bufIndex;
|
||||
shape->bufferInfo->lastCommand += 1;
|
||||
dg.shape2DCommandCounter = shape->bufferInfo->lastCommand;
|
||||
AddCommand(&dg);
|
||||
offset = osave;
|
||||
}
|
||||
|
@ -1082,6 +1084,17 @@ void F2DDrawer::Clear()
|
|||
screenFade = 1.f;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void F2DDrawer::OnFrameDone()
|
||||
{
|
||||
buffersToDestroy.Clear();
|
||||
}
|
||||
|
||||
F2DVertexBuffer::F2DVertexBuffer()
|
||||
{
|
||||
mVertexBuffer = screen->CreateVertexBuffer();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "textures.h"
|
||||
#include "renderstyle.h"
|
||||
#include "dobject.h"
|
||||
#include "refcounted.h"
|
||||
|
||||
struct DrawParms;
|
||||
struct FColormap;
|
||||
|
@ -49,6 +50,7 @@ struct F2DPolygons
|
|||
};
|
||||
|
||||
class DShape2D;
|
||||
struct DShape2DBufferInfo;
|
||||
|
||||
class F2DDrawer
|
||||
{
|
||||
|
@ -123,7 +125,7 @@ public:
|
|||
bool useTransform;
|
||||
DMatrix3x3 transform;
|
||||
|
||||
DShape2D* shape2D;
|
||||
RefCountedPtr<DShape2DBufferInfo> shape2DBufInfo;
|
||||
int shape2DBufIndex;
|
||||
int shape2DIndexCount;
|
||||
int shape2DCommandCounter;
|
||||
|
@ -136,7 +138,7 @@ public:
|
|||
// If these fields match, two draw commands can be batched.
|
||||
bool isCompatible(const RenderCommand &other) const
|
||||
{
|
||||
if (shape2D != nullptr || other.shape2D != nullptr) return false;
|
||||
if (shape2DBufInfo != nullptr || other.shape2DBufInfo != nullptr) return false;
|
||||
return mTexture == other.mTexture &&
|
||||
mType == other.mType &&
|
||||
mTranslationId == other.mTranslationId &&
|
||||
|
@ -214,6 +216,7 @@ public:
|
|||
void Begin(int w, int h) { isIn2D = true; Width = w; Height = h; }
|
||||
void End() { isIn2D = false; }
|
||||
bool HasBegun2D() { return isIn2D; }
|
||||
void OnFrameDone();
|
||||
|
||||
void ClearClipRect() { clipleft = cliptop = 0; clipwidth = clipheight = -1; }
|
||||
void SetClipRect(int x, int y, int w, int h);
|
||||
|
@ -240,12 +243,22 @@ public:
|
|||
bool mIsFirstPass = true;
|
||||
};
|
||||
|
||||
struct DShape2DBufferInfo : NoVirtualRefCountedBase
|
||||
{
|
||||
TArray<F2DVertexBuffer> buffers;
|
||||
bool needsVertexUpload = true;
|
||||
int bufIndex = -1;
|
||||
int lastCommand = -1;
|
||||
bool uploadedOnce = false;
|
||||
};
|
||||
|
||||
class DShape2D : public DObject
|
||||
{
|
||||
|
||||
DECLARE_CLASS(DShape2D,DObject)
|
||||
public:
|
||||
DShape2D()
|
||||
: bufferInfo(new DShape2DBufferInfo)
|
||||
{
|
||||
transform.Identity();
|
||||
}
|
||||
|
@ -261,12 +274,8 @@ public:
|
|||
|
||||
DMatrix3x3 transform;
|
||||
|
||||
TArray<F2DVertexBuffer> buffers;
|
||||
bool needsVertexUpload = true;
|
||||
int bufIndex = -1;
|
||||
int lastCommand = -1;
|
||||
RefCountedPtr<DShape2DBufferInfo> bufferInfo;
|
||||
|
||||
bool uploadedOnce = false;
|
||||
DrawParms* lastParms;
|
||||
|
||||
void OnDestroy() override;
|
||||
|
|
|
@ -859,7 +859,7 @@ void S_StopMusic (bool force)
|
|||
|
||||
CCMD (changemus)
|
||||
{
|
||||
if (!nomusic)
|
||||
if (MusicEnabled())
|
||||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
|
|
|
@ -450,7 +450,7 @@ SoundHandle SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int length)
|
|||
}
|
||||
|
||||
// Second pass to write the data
|
||||
if (okay)
|
||||
if (okay && len > 0)
|
||||
{
|
||||
data = new uint8_t[len];
|
||||
i = 26;
|
||||
|
|
|
@ -291,7 +291,7 @@ void FCommandBuffer::AddString(FString clip)
|
|||
if (clip.IsNotEmpty())
|
||||
{
|
||||
// Only paste the first line.
|
||||
long brk = clip.IndexOfAny("\r\n\b");
|
||||
auto brk = clip.IndexOfAny("\r\n\b");
|
||||
std::u32string build;
|
||||
if (brk >= 0)
|
||||
{
|
||||
|
|
|
@ -839,11 +839,11 @@ int FColorCVar::ToInt2 (UCVarValue value, ECVarType type)
|
|||
|
||||
if (string.IsNotEmpty())
|
||||
{
|
||||
ret = V_GetColorFromString (NULL, string);
|
||||
ret = V_GetColorFromString (string);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = V_GetColorFromString (NULL, value.String);
|
||||
ret = V_GetColorFromString (value.String);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -533,7 +533,7 @@ FString BuildString (int argc, FString *argv)
|
|||
else if (strchr(argv[arg], '"'))
|
||||
{ // If it contains one or more quotes, we need to escape them.
|
||||
buf << '"';
|
||||
long substr_start = 0, quotepos;
|
||||
ptrdiff_t substr_start = 0, quotepos;
|
||||
while ((quotepos = argv[arg].IndexOf('"', substr_start)) >= 0)
|
||||
{
|
||||
if (substr_start < quotepos)
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "s_music.h"
|
||||
#include "m_argv.h"
|
||||
#include "i_interface.h"
|
||||
#include "gamecontrol.h"
|
||||
|
||||
CVAR(Bool, inter_subtitles, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ extern uint8_t IcePalette[16][3];
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PaletteContainer::Init(int numslots) // This cannot be a constructor!!!
|
||||
void PaletteContainer::Init(int numslots, const uint8_t* indexmap) // This cannot be a constructor!!!
|
||||
{
|
||||
if (numslots < 1) numslots = 1;
|
||||
Clear();
|
||||
|
@ -63,6 +63,7 @@ void PaletteContainer::Init(int numslots) // This cannot be a constructor!!!
|
|||
TranslationTables.Resize(numslots);
|
||||
StoreTranslation(0, &remap); // make sure that translation ID 0 is the identity.
|
||||
ColorMatcher.SetPalette(BaseColors);
|
||||
ColorMatcher.SetIndexMap(indexmap);
|
||||
}
|
||||
|
||||
void PaletteContainer::SetPalette(const uint8_t* colors, int transparent_index)
|
||||
|
|
|
@ -116,7 +116,7 @@ private:
|
|||
FMemArena remapArena;
|
||||
TArray<TAutoGrowArray<FRemapTablePtr, FRemapTable*>> TranslationTables;
|
||||
public:
|
||||
void Init(int numslots); // This cannot be a constructor!!!
|
||||
void Init(int numslots, const uint8_t *indexmap); // This cannot be a constructor!!!
|
||||
void SetPalette(const uint8_t* colors, int transparent_index = -1);
|
||||
void Clear();
|
||||
int DetermineTranslucency(FileReader& file);
|
||||
|
|
|
@ -435,7 +435,7 @@ void FStringTable::InsertString(int lumpnum, int langid, FName label, const FStr
|
|||
{
|
||||
const char *strlangid = (const char *)&langid;
|
||||
TableElement te = { fileSystem.GetFileContainer(lumpnum), { string, string, string, string } };
|
||||
long index;
|
||||
ptrdiff_t index;
|
||||
while ((index = te.strings[0].IndexOf("@[")) >= 0)
|
||||
{
|
||||
auto endindex = te.strings[0].IndexOf(']', index);
|
||||
|
|
|
@ -208,8 +208,9 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
|
|||
char *dirptr = (char*)directory;
|
||||
FZipLump *lump_p = Lumps;
|
||||
|
||||
FString name0;
|
||||
FString name0, name1;
|
||||
bool foundspeciallump = false;
|
||||
bool foundprefix = false;
|
||||
|
||||
// Check if all files have the same prefix so that this can be stripped out.
|
||||
// This will only be done if there is either a MAPINFO, ZMAPINFO or GAMEINFO lump in the subdirectory, denoting a ZDoom mod.
|
||||
|
@ -233,32 +234,42 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter)
|
|||
}
|
||||
|
||||
name.ToLower();
|
||||
if (name.IndexOf("filter/") == 0)
|
||||
continue; // 'filter' is a reserved name of the file system.
|
||||
if (name.IndexOf("__macosx") == 0)
|
||||
continue; // skip Apple garbage. At this stage only the root folder matters,
|
||||
if (i == 0)
|
||||
continue; // skip Apple garbage. At this stage only the root folder matters.
|
||||
if (!foundprefix)
|
||||
{
|
||||
// check for special names, if one of these gets found this must be treated as a normal zip.
|
||||
bool isspecial = name.IndexOf("/") < 0 || (filter && filter->reservedFolders.Find(name) < filter->reservedFolders.Size());
|
||||
if (isspecial) break;
|
||||
name0 = name.Left(name.LastIndexOf("/")+1);
|
||||
name1 = name.Left(name.IndexOf("/") + 1);
|
||||
foundprefix = true;
|
||||
}
|
||||
else
|
||||
|
||||
if (name.IndexOf(name0) != 0)
|
||||
{
|
||||
if (name.IndexOf(name0) != 0)
|
||||
if (name1.IsNotEmpty())
|
||||
{
|
||||
name0 = "";
|
||||
break;
|
||||
name0 = name1;
|
||||
if (name.IndexOf(name0) != 0)
|
||||
{
|
||||
name0 = "";
|
||||
}
|
||||
}
|
||||
else if (!foundspeciallump && filter)
|
||||
{
|
||||
// at least one of the more common definition lumps must be present.
|
||||
for (auto &p : filter->requiredPrefixes)
|
||||
{
|
||||
if (name.IndexOf(name0 + p) == 0 || name.LastIndexOf(p) == name.Len() - strlen(p))
|
||||
{
|
||||
foundspeciallump = true;
|
||||
break;
|
||||
}
|
||||
if (name0.IsEmpty())
|
||||
break;
|
||||
}
|
||||
if (!foundspeciallump && filter)
|
||||
{
|
||||
// at least one of the more common definition lumps must be present.
|
||||
for (auto &p : filter->requiredPrefixes)
|
||||
{
|
||||
if (name.IndexOf(name0 + p) == 0 || name.LastIndexOf(p) == name.Len() - strlen(p))
|
||||
{
|
||||
foundspeciallump = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,20 @@ struct FileSystem::LumpRecord
|
|||
if (Namespace == ns_hidden) shortName.qword = 0;
|
||||
else
|
||||
{
|
||||
long slash = longName.LastIndexOf('/');
|
||||
ptrdiff_t encodedResID = longName.LastIndexOf(".{");
|
||||
if (resourceId == -1 && encodedResID >= 0)
|
||||
{
|
||||
const char* p = longName.GetChars() + encodedResID;
|
||||
char* q;
|
||||
int id = (int)strtoull(p+2, &q, 10); // only decimal numbers allowed here.
|
||||
if (q[0] == '}' && (q[1] == '.' || q[1] == 0))
|
||||
{
|
||||
FString toDelete(p, q - p + 1);
|
||||
longName.Substitute(toDelete, "");
|
||||
resourceId = id;
|
||||
}
|
||||
}
|
||||
ptrdiff_t slash = longName.LastIndexOf('/');
|
||||
FString base = (slash >= 0) ? longName.Mid(slash + 1) : longName;
|
||||
auto dot = base.LastIndexOf('.');
|
||||
if (dot >= 0) base.Truncate(dot);
|
||||
|
@ -899,6 +912,12 @@ LumpShortName& FileSystem::GetShortName(int i)
|
|||
return FileInfo[i].shortName;
|
||||
}
|
||||
|
||||
FString& FileSystem::GetLongName(int i)
|
||||
{
|
||||
if ((unsigned)i >= NumEntries) I_Error("GetLongName: Invalid index");
|
||||
return FileInfo[i].longName;
|
||||
}
|
||||
|
||||
void FileSystem::RenameFile(int num, const char* newfn)
|
||||
{
|
||||
if ((unsigned)num >= NumEntries) I_Error("RenameFile: Invalid index");
|
||||
|
@ -1533,7 +1552,7 @@ bool FileSystem::CreatePathlessCopy(const char *name, int id, int /*flags*/)
|
|||
if (lump < 0) return false; // Does not exist.
|
||||
|
||||
auto oldlump = FileInfo[lump];
|
||||
int slash = oldlump.longName.LastIndexOf('/');
|
||||
ptrdiff_t slash = oldlump.longName.LastIndexOf('/');
|
||||
|
||||
if (slash == -1)
|
||||
{
|
||||
|
|
|
@ -117,6 +117,7 @@ public:
|
|||
}
|
||||
|
||||
LumpShortName& GetShortName(int i); // may only be called before the hash chains are set up.
|
||||
FString& GetLongName(int i); // may only be called before the hash chains are set up.
|
||||
void RenameFile(int num, const char* fn);
|
||||
bool CreatePathlessCopy(const char* name, int id, int flags);
|
||||
|
||||
|
|
|
@ -348,8 +348,8 @@ void FResourceFile::PostProcessArchive(void *lumps, size_t lumpsize, LumpFilterI
|
|||
uint32_t max = NumLumps;
|
||||
max -= FilterLumpsByGameType(filter, lumps, lumpsize, max);
|
||||
|
||||
long len;
|
||||
int lastpos = -1;
|
||||
ptrdiff_t len;
|
||||
ptrdiff_t lastpos = -1;
|
||||
FString file;
|
||||
FString LumpFilter = filter->dotFilter;
|
||||
while ((len = LumpFilter.IndexOf('.', lastpos+1)) > 0)
|
||||
|
|
|
@ -437,7 +437,7 @@ void FFont::ReadSheetFont(TArray<FolderEntry> &folderdata, int width, int height
|
|||
Chars[i].OriginalPic->CopySize(*lump, true);
|
||||
if (Chars[i].OriginalPic != *lump) TexMan.AddGameTexture(Chars[i].OriginalPic);
|
||||
}
|
||||
Chars[i].XMove = width;
|
||||
Chars[i].XMove = int(width / Scale.X);
|
||||
}
|
||||
|
||||
if (map1252)
|
||||
|
|
|
@ -407,6 +407,7 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data)
|
|||
count = LastChar - FirstChar + 1;
|
||||
Chars.Resize(count);
|
||||
// BMF palettes are only six bits per component. Fix that.
|
||||
Palette[0] = 0;
|
||||
for (i = 0; i < ActiveColors; ++i)
|
||||
{
|
||||
int r = (data[17 + i * 3] << 2) | (data[17 + i * 3] >> 4);
|
||||
|
|
|
@ -415,19 +415,19 @@ void V_InitFontColors ()
|
|||
else if (sc.Compare ("Flat:"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
logcolor = V_GetColor (nullptr, sc);
|
||||
logcolor = V_GetColor (sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get first color
|
||||
c = V_GetColor (nullptr, sc);
|
||||
c = V_GetColor (sc);
|
||||
tparm.Start[0] = RPART(c);
|
||||
tparm.Start[1] = GPART(c);
|
||||
tparm.Start[2] = BPART(c);
|
||||
|
||||
// Get second color
|
||||
sc.MustGetString();
|
||||
c = V_GetColor (nullptr, sc);
|
||||
c = V_GetColor (sc);
|
||||
tparm.End[0] = RPART(c);
|
||||
tparm.End[1] = GPART(c);
|
||||
tparm.End[2] = BPART(c);
|
||||
|
@ -681,13 +681,13 @@ void V_ApplyLuminosityTranslation(int translation, uint8_t* pixel, int size)
|
|||
int index = clamp(lumadjust, 0, 255);
|
||||
PalEntry newcol = remap[index];
|
||||
// extend the range if we find colors outside what initial analysis provided.
|
||||
if (gray < lum_min)
|
||||
if (gray < lum_min && lum_min != 0)
|
||||
{
|
||||
newcol.r = newcol.r * gray / lum_min;
|
||||
newcol.g = newcol.g * gray / lum_min;
|
||||
newcol.b = newcol.b * gray / lum_min;
|
||||
}
|
||||
else if (gray > lum_max)
|
||||
else if (gray > lum_max && lum_max != 0)
|
||||
{
|
||||
newcol.r = clamp(newcol.r * gray / lum_max, 0, 255);
|
||||
newcol.g = clamp(newcol.g * gray / lum_max, 0, 255);
|
||||
|
|
|
@ -88,7 +88,7 @@ TArray<FBrokenLines> V_BreakLines (FFont *font, int maxwidth, const uint8_t *str
|
|||
{
|
||||
if (*string == '[')
|
||||
{
|
||||
const uint8_t *start = string;
|
||||
const uint8_t* start = string;
|
||||
while (*string != ']' && *string != '\0')
|
||||
{
|
||||
string++;
|
||||
|
@ -97,11 +97,6 @@ TArray<FBrokenLines> V_BreakLines (FFont *font, int maxwidth, const uint8_t *str
|
|||
{
|
||||
string++;
|
||||
}
|
||||
lastcolor = FString((const char *)start, string - start);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastcolor = *string++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
@ -130,6 +125,33 @@ TArray<FBrokenLines> V_BreakLines (FFont *font, int maxwidth, const uint8_t *str
|
|||
}
|
||||
|
||||
auto index = Lines.Reserve(1);
|
||||
for (const uint8_t* pos = start; pos < space; pos++)
|
||||
{
|
||||
if (*pos == TEXTCOLOR_ESCAPE)
|
||||
{
|
||||
pos++;
|
||||
if (*pos)
|
||||
{
|
||||
if (*pos == '[')
|
||||
{
|
||||
const uint8_t* cstart = pos;
|
||||
while (*pos != ']' && *pos != '\0')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
if (*pos != '\0')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
lastcolor = FString((const char*)cstart, pos - start);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastcolor = *pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
breakit (&Lines[index], font, start, space, linecolor);
|
||||
if (c == '\n' && !preservecolor)
|
||||
{
|
||||
|
|
|
@ -1036,6 +1036,7 @@ DEFINE_FIELD(DListMenuDescriptor, mFont)
|
|||
DEFINE_FIELD(DListMenuDescriptor, mFontColor)
|
||||
DEFINE_FIELD(DListMenuDescriptor, mFontColor2)
|
||||
DEFINE_FIELD(DListMenuDescriptor, mAnimatedTransition)
|
||||
DEFINE_FIELD(DListMenuDescriptor, mAnimated)
|
||||
DEFINE_FIELD(DListMenuDescriptor, mCenter)
|
||||
DEFINE_FIELD(DListMenuDescriptor, mVirtWidth)
|
||||
DEFINE_FIELD(DListMenuDescriptor, mVirtHeight)
|
||||
|
@ -1066,6 +1067,7 @@ DEFINE_FIELD(DImageScrollerDescriptor, textBackgroundBrightness)
|
|||
DEFINE_FIELD(DImageScrollerDescriptor,textFont)
|
||||
DEFINE_FIELD(DImageScrollerDescriptor, textScale)
|
||||
DEFINE_FIELD(DImageScrollerDescriptor, mAnimatedTransition)
|
||||
DEFINE_FIELD(DImageScrollerDescriptor, mAnimated)
|
||||
DEFINE_FIELD(DImageScrollerDescriptor, virtWidth)
|
||||
DEFINE_FIELD(DImageScrollerDescriptor, virtHeight)
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@ public:
|
|||
FFont *textFont;
|
||||
double textScale;
|
||||
bool mAnimatedTransition;
|
||||
bool mAnimated;
|
||||
int virtWidth, virtHeight;
|
||||
|
||||
};
|
||||
|
|
|
@ -344,6 +344,10 @@ static void DoParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc, bool &s
|
|||
{
|
||||
desc->mAnimatedTransition = true;
|
||||
}
|
||||
else if (sc.Compare("animated"))
|
||||
{
|
||||
desc->mAnimated = true;
|
||||
}
|
||||
else if (sc.Compare("MouseWindow"))
|
||||
{
|
||||
sc.MustGetNumber();
|
||||
|
@ -459,7 +463,7 @@ static void DoParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc, bool &s
|
|||
}
|
||||
else if (args[i] == TypeColor)
|
||||
{
|
||||
params.Push(V_GetColor(nullptr, sc));
|
||||
params.Push(V_GetColor(sc));
|
||||
}
|
||||
else if (args[i] == TypeFont)
|
||||
{
|
||||
|
@ -1028,7 +1032,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc, int i
|
|||
}
|
||||
else if (args[i] == TypeColor)
|
||||
{
|
||||
params.Push(V_GetColor(nullptr, sc));
|
||||
params.Push(V_GetColor(sc));
|
||||
}
|
||||
else if (args[i]->isIntCompatible())
|
||||
{
|
||||
|
@ -1212,6 +1216,10 @@ static void ParseImageScrollerBody(FScanner& sc, DImageScrollerDescriptor* desc)
|
|||
{
|
||||
desc->mAnimatedTransition = true;
|
||||
}
|
||||
else if (sc.Compare("animated"))
|
||||
{
|
||||
desc->mAnimated = true;
|
||||
}
|
||||
else if (sc.Compare("textBackground"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
|
@ -1274,7 +1282,7 @@ static void ParseImageScrollerBody(FScanner& sc, DImageScrollerDescriptor* desc)
|
|||
}
|
||||
else if (args[i] == TypeColor)
|
||||
{
|
||||
params.Push(V_GetColor(nullptr, sc));
|
||||
params.Push(V_GetColor(sc));
|
||||
}
|
||||
else if (args[i]->isIntCompatible())
|
||||
{
|
||||
|
|
|
@ -90,8 +90,8 @@ static int FindGFXFile(FString & fn)
|
|||
if (lump != -1) return lump;
|
||||
|
||||
int best = -1;
|
||||
int dot = fn.LastIndexOf('.');
|
||||
int slash = fn.LastIndexOf('/');
|
||||
auto dot = fn.LastIndexOf('.');
|
||||
auto slash = fn.LastIndexOf('/');
|
||||
if (dot > slash) fn.Truncate(dot);
|
||||
|
||||
static const char * extensions[] = { ".png", ".jpg", ".tga", ".pcx", nullptr };
|
||||
|
|
|
@ -44,8 +44,8 @@ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length
|
|||
{
|
||||
// Ensure usemtl statements remain intact
|
||||
TArray<FString> mtlUsages;
|
||||
TArray<long> mtlUsageIdxs;
|
||||
long bpos = 0, nlpos = 0, slashpos = 0;
|
||||
TArray<ptrdiff_t> mtlUsageIdxs;
|
||||
ptrdiff_t bpos = 0, nlpos = 0, slashpos = 0;
|
||||
while (1)
|
||||
{
|
||||
bpos = objBuf.IndexOf("\nusemtl", bpos);
|
||||
|
@ -58,7 +58,7 @@ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length
|
|||
}
|
||||
if (nlpos == -1)
|
||||
{
|
||||
nlpos = (long)objBuf.Len();
|
||||
nlpos = objBuf.Len();
|
||||
}
|
||||
FString lineStr(objBuf.GetChars() + bpos, nlpos - bpos);
|
||||
mtlUsages.Push(lineStr);
|
||||
|
@ -76,7 +76,7 @@ bool FOBJModel::Load(const char* fn, int lumpnum, const char* buffer, int length
|
|||
nlpos = objBuf.IndexOf('\n', bpos);
|
||||
if (nlpos == -1)
|
||||
{
|
||||
nlpos = (long)objBuf.Len();
|
||||
nlpos = objBuf.Len();
|
||||
}
|
||||
memcpy(wObjBuf + bpos, mtlUsages[i].GetChars(), nlpos - bpos);
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ static uint8_t *GetVoxelRemap(const uint8_t *pal)
|
|||
{
|
||||
// The voxel palette uses VGA colors, so we have to expand it
|
||||
// from 6 to 8 bits per component.
|
||||
remap[i] = BestColor((uint32_t *)GPalette.BaseColors,
|
||||
remap[i] = ColorMatcher.Pick(
|
||||
(oldpal[i*3 + 0] << 2) | (oldpal[i*3 + 0] >> 4),
|
||||
(oldpal[i*3 + 1] << 2) | (oldpal[i*3 + 1] >> 4),
|
||||
(oldpal[i*3 + 2] << 2) | (oldpal[i*3 + 2] >> 4));
|
||||
|
|
|
@ -131,7 +131,7 @@ static bool ReadSystemVersionFromPlist(NSOperatingSystemVersion& version)
|
|||
if (const char *patchVersionString = strstr(minorVersionString, "."))
|
||||
{
|
||||
patchVersionString++;
|
||||
plistVersion.patchVersion = atoi(minorVersionString);
|
||||
plistVersion.patchVersion = atoi(patchVersionString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ void Mac_I_FatalError(const char* errortext);
|
|||
void Unix_I_FatalError(const char* errortext)
|
||||
{
|
||||
// Close window or exit fullscreen and release mouse capture
|
||||
SDL_Quit();
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
|
||||
const char *str;
|
||||
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
|
||||
|
@ -204,7 +204,7 @@ void I_PrintStr(const char *cp)
|
|||
{ // gray
|
||||
if (v < 0.33) attrib = 0x8;
|
||||
else if (v < 0.90) attrib = 0x7;
|
||||
else attrib = 0x15;
|
||||
else attrib = 0xF;
|
||||
}
|
||||
|
||||
printData.AppendFormat("\033[%um",((attrib & 0x8) ? 90 : 30) + (attrib & 0x7));
|
||||
|
|
|
@ -116,8 +116,6 @@ CCMD(vid_list_sdl_render_drivers)
|
|||
|
||||
namespace Priv
|
||||
{
|
||||
static const uint32_t VulkanWindowFlag = SDL_WINDOW_VULKAN;
|
||||
|
||||
SDL_Window *window;
|
||||
bool vulkanEnabled;
|
||||
bool softpolyEnabled;
|
||||
|
@ -409,7 +407,7 @@ SDLVideo::SDLVideo ()
|
|||
|
||||
if (Priv::vulkanEnabled)
|
||||
{
|
||||
Priv::CreateWindow(Priv::VulkanWindowFlag | SDL_WINDOW_HIDDEN);
|
||||
Priv::CreateWindow(SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN | (vid_fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0));
|
||||
|
||||
if (Priv::window == nullptr)
|
||||
{
|
||||
|
|
|
@ -545,6 +545,20 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool restartrequest;
|
||||
|
||||
void CheckForRestart()
|
||||
{
|
||||
if (restartrequest)
|
||||
{
|
||||
HMODULE hModule = GetModuleHandleW(NULL);
|
||||
WCHAR path[MAX_PATH];
|
||||
GetModuleFileNameW(hModule, path, MAX_PATH);
|
||||
ShellExecuteW(NULL, L"open", path, GetCommandLineW(), NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
restartrequest = false;
|
||||
}
|
||||
|
||||
INT_PTR CALLBACK ErrorPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg)
|
||||
|
@ -559,11 +573,7 @@ INT_PTR CALLBACK ErrorPaneProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara
|
|||
{
|
||||
if (LOWORD(wParam) == IDC_BUTTON1) // we pressed the restart button, so run GZDoom again
|
||||
{
|
||||
HMODULE hModule = GetModuleHandleW(NULL);
|
||||
WCHAR path[MAX_PATH];
|
||||
GetModuleFileNameW(hModule, path, MAX_PATH);
|
||||
|
||||
ShellExecuteW(NULL, L"open", path, GetCommandLineW(), NULL, SW_SHOWNORMAL);
|
||||
restartrequest = true;
|
||||
}
|
||||
PostQuitMessage (0);
|
||||
return TRUE;
|
||||
|
@ -969,6 +979,8 @@ int DoMain (HINSTANCE hInstance)
|
|||
atexit (UnCOM);
|
||||
|
||||
int ret = GameMain ();
|
||||
CheckForRestart();
|
||||
|
||||
DestroyCustomCursor();
|
||||
if (ret == 1337) // special exit code for 'norun'.
|
||||
{
|
||||
|
|
|
@ -52,15 +52,15 @@ static bool IsGlslWhitespace(char c)
|
|||
}
|
||||
}
|
||||
|
||||
static FString NextGlslToken(const char *chars, long len, long &pos)
|
||||
static FString NextGlslToken(const char *chars, ptrdiff_t len, ptrdiff_t &pos)
|
||||
{
|
||||
// Eat whitespace
|
||||
long tokenStart = pos;
|
||||
ptrdiff_t tokenStart = pos;
|
||||
while (tokenStart != len && IsGlslWhitespace(chars[tokenStart]))
|
||||
tokenStart++;
|
||||
|
||||
// Find token end
|
||||
long tokenEnd = tokenStart;
|
||||
ptrdiff_t tokenEnd = tokenStart;
|
||||
while (tokenEnd != len && !IsGlslWhitespace(chars[tokenEnd]) && chars[tokenEnd] != ';')
|
||||
tokenEnd++;
|
||||
|
||||
|
@ -82,13 +82,13 @@ FString RemoveLegacyUserUniforms(FString code)
|
|||
|
||||
// The following code searches for legacy uniform declarations in the shader itself and replaces them with whitespace.
|
||||
|
||||
long len = (long)code.Len();
|
||||
ptrdiff_t len = code.Len();
|
||||
char *chars = code.LockBuffer();
|
||||
|
||||
long startIndex = 0;
|
||||
ptrdiff_t startIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
long matchIndex = code.IndexOf("uniform", startIndex);
|
||||
ptrdiff_t matchIndex = code.IndexOf("uniform", startIndex);
|
||||
if (matchIndex == -1)
|
||||
break;
|
||||
|
||||
|
@ -98,7 +98,7 @@ FString RemoveLegacyUserUniforms(FString code)
|
|||
bool isKeywordEnd = matchIndex + 7 == len || IsGlslWhitespace(chars[matchIndex + 7]);
|
||||
if (isKeywordStart && isKeywordEnd)
|
||||
{
|
||||
long pos = matchIndex + 7;
|
||||
ptrdiff_t pos = matchIndex + 7;
|
||||
FString type = NextGlslToken(chars, len, pos);
|
||||
FString identifier = NextGlslToken(chars, len, pos);
|
||||
|
||||
|
@ -107,10 +107,10 @@ FString RemoveLegacyUserUniforms(FString code)
|
|||
|
||||
if (isLegacyUniformName)
|
||||
{
|
||||
long statementEndIndex = code.IndexOf(';', matchIndex + 7);
|
||||
ptrdiff_t statementEndIndex = code.IndexOf(';', matchIndex + 7);
|
||||
if (statementEndIndex == -1)
|
||||
statementEndIndex = len;
|
||||
for (long i = matchIndex; i <= statementEndIndex; i++)
|
||||
for (ptrdiff_t i = matchIndex; i <= statementEndIndex; i++)
|
||||
{
|
||||
if (!IsGlslWhitespace(chars[i]))
|
||||
chars[i] = ' ';
|
||||
|
@ -127,7 +127,7 @@ FString RemoveLegacyUserUniforms(FString code)
|
|||
// Modern GLSL only allows use of 'texture'.
|
||||
while (true)
|
||||
{
|
||||
long matchIndex = code.IndexOf("texture2d", startIndex);
|
||||
ptrdiff_t matchIndex = code.IndexOf("texture2d", startIndex);
|
||||
if (matchIndex == -1)
|
||||
break;
|
||||
|
||||
|
@ -148,14 +148,14 @@ FString RemoveLegacyUserUniforms(FString code)
|
|||
|
||||
FString RemoveSamplerBindings(FString code, TArray<std::pair<FString, int>> &samplerstobind)
|
||||
{
|
||||
long len = (long)code.Len();
|
||||
ptrdiff_t len = code.Len();
|
||||
char *chars = code.LockBuffer();
|
||||
|
||||
long startIndex = 0;
|
||||
long startpos, endpos;
|
||||
ptrdiff_t startIndex = 0;
|
||||
ptrdiff_t startpos, endpos;
|
||||
while (true)
|
||||
{
|
||||
long matchIndex = code.IndexOf("layout(binding", startIndex);
|
||||
ptrdiff_t matchIndex = code.IndexOf("layout(binding", startIndex);
|
||||
if (matchIndex == -1)
|
||||
break;
|
||||
|
||||
|
@ -165,7 +165,7 @@ FString RemoveSamplerBindings(FString code, TArray<std::pair<FString, int>> &sam
|
|||
bool isKeywordEnd = matchIndex + 14 == len || IsGlslWhitespace(chars[matchIndex + 14]) || chars[matchIndex + 14] == '=';
|
||||
if (isKeywordStart && isKeywordEnd)
|
||||
{
|
||||
long pos = matchIndex + 14;
|
||||
ptrdiff_t pos = matchIndex + 14;
|
||||
startpos = matchIndex;
|
||||
while (IsGlslWhitespace(chars[pos])) pos++;
|
||||
if (chars[pos] == '=')
|
||||
|
@ -175,7 +175,7 @@ FString RemoveSamplerBindings(FString code, TArray<std::pair<FString, int>> &sam
|
|||
auto val = strtol(&chars[pos], &p, 0);
|
||||
if (p != &chars[pos])
|
||||
{
|
||||
pos = long(p - chars);
|
||||
pos = (p - chars);
|
||||
while (IsGlslWhitespace(chars[pos])) pos++;
|
||||
if (chars[pos] == ')')
|
||||
{
|
||||
|
@ -216,17 +216,17 @@ FString RemoveSamplerBindings(FString code, TArray<std::pair<FString, int>> &sam
|
|||
|
||||
FString RemoveLayoutLocationDecl(FString code, const char *inoutkeyword)
|
||||
{
|
||||
long len = (long)code.Len();
|
||||
ptrdiff_t len = code.Len();
|
||||
char *chars = code.LockBuffer();
|
||||
|
||||
long startIndex = 0;
|
||||
ptrdiff_t startIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
long matchIndex = code.IndexOf("layout(location", startIndex);
|
||||
ptrdiff_t matchIndex = code.IndexOf("layout(location", startIndex);
|
||||
if (matchIndex == -1)
|
||||
break;
|
||||
|
||||
long endIndex = matchIndex;
|
||||
ptrdiff_t endIndex = matchIndex;
|
||||
|
||||
// Find end of layout declaration
|
||||
while (chars[endIndex] != ')' && chars[endIndex] != 0)
|
||||
|
@ -255,7 +255,7 @@ FString RemoveLayoutLocationDecl(FString code, const char *inoutkeyword)
|
|||
if (keywordFound && IsGlslWhitespace(chars[endIndex + i]))
|
||||
{
|
||||
// yes - replace declaration with spaces
|
||||
for (long i = matchIndex; i < endIndex; i++)
|
||||
for (auto i = matchIndex; i < endIndex; i++)
|
||||
chars[i] = ' ';
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,8 @@ bool IShadowMap::PerformUpdate()
|
|||
LightsProcessed = 0;
|
||||
LightsShadowmapped = 0;
|
||||
|
||||
if (gl_light_shadowmap && (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER) && CollectLights != nullptr)
|
||||
// CollectLights will be null if the calling code decides that shadowmaps are not needed.
|
||||
if (CollectLights != nullptr)
|
||||
{
|
||||
UpdateCycles.Clock();
|
||||
UploadAABBTree();
|
||||
|
|
|
@ -57,6 +57,11 @@ public:
|
|||
mLights[index + 3] = r;
|
||||
}
|
||||
|
||||
bool Enabled() const
|
||||
{
|
||||
return mAABBTree != nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Upload the AABB-tree to the GPU
|
||||
void UploadAABBTree();
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
#include "i_interface.h"
|
||||
|
||||
// Set up 3D-specific console variables:
|
||||
CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG)
|
||||
CVAR(Int, vr_mode, 0, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
|
||||
|
||||
// switch left and right eye views
|
||||
CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, vr_swap_eyes, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
|
||||
|
||||
// intraocular distance in meters
|
||||
CVAR(Float, vr_ipd, 0.062f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // METERS
|
||||
|
|
|
@ -178,22 +178,22 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state)
|
|||
state.EnableTexture(false);
|
||||
}
|
||||
|
||||
if (cmd.shape2D != nullptr)
|
||||
if (cmd.shape2DBufInfo != nullptr)
|
||||
{
|
||||
state.SetVertexBuffer(&cmd.shape2D->buffers[cmd.shape2DBufIndex]);
|
||||
state.SetVertexBuffer(&cmd.shape2DBufInfo->buffers[cmd.shape2DBufIndex]);
|
||||
state.DrawIndexed(DT_Triangles, 0, cmd.shape2DIndexCount);
|
||||
state.SetVertexBuffer(&vb);
|
||||
if (cmd.shape2DCommandCounter == cmd.shape2D->lastCommand)
|
||||
if (cmd.shape2DCommandCounter == cmd.shape2DBufInfo->lastCommand)
|
||||
{
|
||||
cmd.shape2D->lastCommand = -1;
|
||||
if (cmd.shape2D->bufIndex > 0)
|
||||
cmd.shape2DBufInfo->lastCommand = -1;
|
||||
if (cmd.shape2DBufInfo->bufIndex > 0)
|
||||
{
|
||||
cmd.shape2D->needsVertexUpload = true;
|
||||
cmd.shape2D->buffers.Clear();
|
||||
cmd.shape2D->bufIndex = -1;
|
||||
cmd.shape2DBufInfo->needsVertexUpload = true;
|
||||
cmd.shape2DBufInfo->buffers.Clear();
|
||||
cmd.shape2DBufInfo->bufIndex = -1;
|
||||
}
|
||||
}
|
||||
cmd.shape2D->uploadedOnce = false;
|
||||
cmd.shape2DBufInfo->uploadedOnce = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1328,7 +1328,7 @@ FxExpression *FxColorCast::Resolve(FCompileContext &ctx)
|
|||
}
|
||||
else
|
||||
{
|
||||
FxExpression *x = new FxConstant(V_GetColor(nullptr, constval.GetString(), &ScriptPosition), ScriptPosition);
|
||||
FxExpression *x = new FxConstant(V_GetColor(constval.GetString(), &ScriptPosition), ScriptPosition);
|
||||
delete this;
|
||||
return x;
|
||||
}
|
||||
|
@ -9823,6 +9823,8 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
|
|||
{
|
||||
CHECKRESOLVED();
|
||||
|
||||
SAFE_RESOLVE(Condition, ctx);
|
||||
|
||||
if (WhenTrue == nullptr && WhenFalse == nullptr)
|
||||
{ // We don't do anything either way, so disappear
|
||||
delete this;
|
||||
|
@ -9830,8 +9832,6 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
|
|||
return new FxNop(ScriptPosition);
|
||||
}
|
||||
|
||||
SAFE_RESOLVE(Condition, ctx);
|
||||
|
||||
if (Condition->ValueType != TypeBool)
|
||||
{
|
||||
Condition = new FxBoolCast(Condition, false);
|
||||
|
|
|
@ -419,7 +419,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, Filter, StringFilter)
|
|||
|
||||
static int StringIndexOf(FString *self, const FString &substr, int startIndex)
|
||||
{
|
||||
return self->IndexOf(substr, startIndex);
|
||||
return (int)self->IndexOf(substr, startIndex);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, IndexOf, StringIndexOf)
|
||||
|
@ -427,12 +427,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, IndexOf, StringIndexOf)
|
|||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_STRING(substr);
|
||||
PARAM_INT(startIndex);
|
||||
ACTION_RETURN_INT(self->IndexOf(substr, startIndex));
|
||||
ACTION_RETURN_INT(StringIndexOf(self, substr, startIndex));
|
||||
}
|
||||
|
||||
static int StringLastIndexOf(FString *self, const FString &substr, int endIndex)
|
||||
{
|
||||
return self->LastIndexOfBroken(substr, endIndex);
|
||||
return (int)self->LastIndexOfBroken(substr, endIndex);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, LastIndexOf, StringLastIndexOf)
|
||||
|
@ -440,12 +440,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, LastIndexOf, StringLastIndexOf)
|
|||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_STRING(substr);
|
||||
PARAM_INT(endIndex);
|
||||
ACTION_RETURN_INT(self->LastIndexOfBroken(substr, endIndex));
|
||||
ACTION_RETURN_INT(StringLastIndexOf(self, substr, endIndex));
|
||||
}
|
||||
|
||||
static int StringRightIndexOf(FString *self, const FString &substr, int endIndex)
|
||||
{
|
||||
return self->LastIndexOf(substr, endIndex);
|
||||
return (int)self->LastIndexOf(substr, endIndex);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, RightIndexOf, StringRightIndexOf)
|
||||
|
@ -453,7 +453,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FStringStruct, RightIndexOf, StringRightIndexOf)
|
|||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_STRING(substr);
|
||||
PARAM_INT(endIndex);
|
||||
ACTION_RETURN_INT(self->LastIndexOf(substr, endIndex));
|
||||
ACTION_RETURN_INT(StringRightIndexOf(self, substr, endIndex));
|
||||
}
|
||||
|
||||
static void StringToUpper(FString *self)
|
||||
|
|
|
@ -49,7 +49,7 @@ static int CastS2I(FString *b) { return (int)b->ToLong(); }
|
|||
static double CastS2F(FString *b) { return b->ToDouble(); }
|
||||
static int CastS2N(FString *b) { return b->Len() == 0 ? NAME_None : FName(*b).GetIndex(); }
|
||||
static void CastN2S(FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; }
|
||||
static int CastS2Co(FString *b) { return V_GetColor(nullptr, *b); }
|
||||
static int CastS2Co(FString *b) { return V_GetColor(*b); }
|
||||
static void CastCo2S(FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); }
|
||||
static int CastS2So(FString *b) { return FSoundID(*b); }
|
||||
static void CastSo2S(FString* a, int b) { *a = soundEngine->GetSoundName(b); }
|
||||
|
|
|
@ -1826,7 +1826,7 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c
|
|||
|
||||
case CAST_S2Co:
|
||||
ASSERTD(a); ASSERTS(b);
|
||||
reg.d[a] = V_GetColor(NULL, reg.s[b]);
|
||||
reg.d[a] = V_GetColor(reg.s[b]);
|
||||
break;
|
||||
|
||||
case CAST_Co2S:
|
||||
|
|
|
@ -542,7 +542,7 @@ void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPar
|
|||
if (!sc.CheckNumber())
|
||||
{
|
||||
sc.MustGetString();
|
||||
part.Blend = V_GetColor(NULL, sc);
|
||||
part.Blend = V_GetColor(sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -42,23 +42,21 @@
|
|||
|
||||
#include "palutil.h"
|
||||
|
||||
int BestColor (const uint32_t *pal_in, int r, int g, int b, int first, int num);
|
||||
int BestColor (const uint32_t *pal_in, int r, int g, int b, int first, int num, const uint8_t* indexmap);
|
||||
|
||||
class FColorMatcher
|
||||
{
|
||||
public:
|
||||
FColorMatcher () = default;
|
||||
FColorMatcher (const uint32_t *palette) { Pal = reinterpret_cast<const PalEntry*>(palette); }
|
||||
FColorMatcher (const FColorMatcher &other) = default;
|
||||
|
||||
void SetPalette(PalEntry* palette) { Pal = palette; }
|
||||
void SetPalette (const uint32_t *palette) { Pal = reinterpret_cast<const PalEntry*>(palette); }
|
||||
void SetIndexMap(const uint8_t* index) { indexmap = index; startindex = index ? 0 : 1; }
|
||||
uint8_t Pick (int r, int g, int b)
|
||||
{
|
||||
if (Pal == nullptr)
|
||||
return 1;
|
||||
|
||||
return (uint8_t)BestColor ((uint32_t *)Pal, r, g, b, 1, 255);
|
||||
return (uint8_t)BestColor ((uint32_t *)Pal, r, g, b, startindex, 255, indexmap);
|
||||
}
|
||||
|
||||
uint8_t Pick (PalEntry pe)
|
||||
|
@ -66,10 +64,10 @@ public:
|
|||
return Pick(pe.r, pe.g, pe.b);
|
||||
}
|
||||
|
||||
FColorMatcher &operator= (const FColorMatcher &other) = default;
|
||||
|
||||
private:
|
||||
const PalEntry *Pal;
|
||||
const PalEntry *Pal = nullptr;
|
||||
const uint8_t* indexmap = nullptr;
|
||||
int startindex = 1;
|
||||
};
|
||||
|
||||
extern FColorMatcher ColorMatcher;
|
||||
|
|
|
@ -67,22 +67,14 @@ static uint64_t NSToMS(uint64_t ns)
|
|||
return static_cast<uint64_t>(ns / 1'000'000);
|
||||
}
|
||||
|
||||
static int NSToTic(uint64_t ns)
|
||||
static int NSToTic(uint64_t ns, double const ticrate)
|
||||
{
|
||||
return static_cast<int>(ns * GameTicRate / 1'000'000'000);
|
||||
return static_cast<int>(ns * ticrate / 1'000'000'000);
|
||||
}
|
||||
|
||||
static int NSToBuildTic(uint64_t ns)
|
||||
static uint64_t TicToNS(double tic, double const ticrate)
|
||||
{
|
||||
return static_cast<int>(ns * 120 / 1'000'000'000);
|
||||
}
|
||||
static uint64_t TicToNS(int tic)
|
||||
{
|
||||
return static_cast<uint64_t>(tic) * 1'000'000'000 / GameTicRate;
|
||||
}
|
||||
static uint64_t BuildTicToNS(int tic)
|
||||
{
|
||||
return static_cast<uint64_t>(tic) * 1'000'000'000 / 120;
|
||||
return static_cast<uint64_t>(tic * 1'000'000'000 / ticrate);
|
||||
}
|
||||
|
||||
void I_SetFrameTime()
|
||||
|
@ -111,18 +103,18 @@ void I_WaitVBL(int count)
|
|||
I_SetFrameTime();
|
||||
}
|
||||
|
||||
int I_WaitForTic(int prevtic)
|
||||
int I_WaitForTic(int prevtic, double const ticrate)
|
||||
{
|
||||
// Waits until the current tic is greater than prevtic. Time must not be frozen.
|
||||
|
||||
int time;
|
||||
while ((time = I_GetTime()) <= prevtic)
|
||||
while ((time = I_GetTime(ticrate)) <= prevtic)
|
||||
{
|
||||
// Windows-specific note:
|
||||
// The minimum amount of time a thread can sleep is controlled by timeBeginPeriod.
|
||||
// We set this to 1 ms in DoMain.
|
||||
|
||||
const uint64_t next = FirstFrameStartTime + TicToNS(prevtic + 1);
|
||||
const uint64_t next = FirstFrameStartTime + TicToNS(prevtic + 1, ticrate);
|
||||
const uint64_t now = I_nsTime();
|
||||
|
||||
if (next > now)
|
||||
|
@ -166,21 +158,16 @@ uint64_t I_GetTimeNS()
|
|||
return CurrentFrameStartTime - FirstFrameStartTime;
|
||||
}
|
||||
|
||||
int I_GetTime()
|
||||
int I_GetTime(double const ticrate)
|
||||
{
|
||||
return NSToTic(CurrentFrameStartTime - FirstFrameStartTime);
|
||||
return NSToTic(CurrentFrameStartTime - FirstFrameStartTime, ticrate);
|
||||
}
|
||||
|
||||
int I_GetBuildTime()
|
||||
double I_GetTimeFrac(double const ticrate)
|
||||
{
|
||||
return NSToBuildTic(CurrentFrameStartTime - FirstFrameStartTime);
|
||||
}
|
||||
|
||||
double I_GetTimeFrac()
|
||||
{
|
||||
int currentTic = NSToTic(CurrentFrameStartTime - FirstFrameStartTime);
|
||||
uint64_t ticStartTime = FirstFrameStartTime + TicToNS(currentTic);
|
||||
uint64_t ticNextTime = FirstFrameStartTime + TicToNS(currentTic + 1);
|
||||
int currentTic = NSToTic(CurrentFrameStartTime - FirstFrameStartTime, ticrate);
|
||||
uint64_t ticStartTime = FirstFrameStartTime + TicToNS(currentTic, ticrate);
|
||||
uint64_t ticNextTime = FirstFrameStartTime + TicToNS(currentTic + 1, ticrate);
|
||||
|
||||
return (CurrentFrameStartTime - ticStartTime) / (double)(ticNextTime - ticStartTime);
|
||||
}
|
||||
|
|
|
@ -9,17 +9,14 @@ extern double TimeScale;
|
|||
void I_SetFrameTime();
|
||||
|
||||
// Called by D_DoomLoop, returns current time in tics.
|
||||
int I_GetTime();
|
||||
int I_GetTime(double const ticrate = GameTicRate);
|
||||
// same, but using nanoseconds
|
||||
uint64_t I_GetTimeNS();
|
||||
|
||||
// Called by Build games in lieu of totalclock, returns current time in tics at ticrate of 120.
|
||||
int I_GetBuildTime();
|
||||
|
||||
double I_GetTimeFrac();
|
||||
double I_GetTimeFrac(double const ticrate = GameTicRate);
|
||||
|
||||
// like I_GetTime, except it waits for a new tic before returning
|
||||
int I_WaitForTic(int);
|
||||
int I_WaitForTic(int prevtic, double const ticrate = GameTicRate);
|
||||
|
||||
// Freezes tic counting temporarily. While frozen, calls to I_GetTime()
|
||||
// will always return the same value.
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
/* Palette management stuff */
|
||||
/****************************/
|
||||
|
||||
int BestColor (const uint32_t *pal_in, int r, int g, int b, int first, int num)
|
||||
int BestColor (const uint32_t *pal_in, int r, int g, int b, int first, int num, const uint8_t* indexmap)
|
||||
{
|
||||
const PalEntry *pal = (const PalEntry *)pal_in;
|
||||
int bestcolor = first;
|
||||
|
@ -54,17 +54,18 @@ int BestColor (const uint32_t *pal_in, int r, int g, int b, int first, int num)
|
|||
|
||||
for (int color = first; color < num; color++)
|
||||
{
|
||||
int x = r - pal[color].r;
|
||||
int y = g - pal[color].g;
|
||||
int z = b - pal[color].b;
|
||||
int co = indexmap ? indexmap[color] : color;
|
||||
int x = r - pal[co].r;
|
||||
int y = g - pal[co].g;
|
||||
int z = b - pal[co].b;
|
||||
int dist = x*x + y*y + z*z;
|
||||
if (dist < bestdist)
|
||||
{
|
||||
if (dist == 0)
|
||||
return color;
|
||||
return co;
|
||||
|
||||
bestdist = dist;
|
||||
bestcolor = color;
|
||||
bestcolor = co;
|
||||
}
|
||||
}
|
||||
return bestcolor;
|
||||
|
@ -523,7 +524,7 @@ PalEntry averageColor(const uint32_t* data, int size, int maxout)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int V_GetColorFromString(const uint32_t* palette, const char* cstr, FScriptPosition* sc)
|
||||
int V_GetColorFromString(const char* cstr, FScriptPosition* sc)
|
||||
{
|
||||
int c[3], i, p;
|
||||
char val[3];
|
||||
|
@ -609,10 +610,7 @@ int V_GetColorFromString(const uint32_t* palette, const char* cstr, FScriptPosit
|
|||
}
|
||||
}
|
||||
}
|
||||
if (palette)
|
||||
return BestColor(palette, c[0], c[1], c[2]);
|
||||
else
|
||||
return MAKERGB(c[0], c[1], c[2]);
|
||||
return MAKERGB(c[0], c[1], c[2]);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -715,26 +713,26 @@ FString V_GetColorStringByName(const char* name, FScriptPosition* sc)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int V_GetColor(const uint32_t* palette, const char* str, FScriptPosition* sc)
|
||||
int V_GetColor(const char* str, FScriptPosition* sc)
|
||||
{
|
||||
FString string = V_GetColorStringByName(str, sc);
|
||||
int res;
|
||||
|
||||
if (!string.IsEmpty())
|
||||
{
|
||||
res = V_GetColorFromString(palette, string, sc);
|
||||
res = V_GetColorFromString(string, sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = V_GetColorFromString(palette, str, sc);
|
||||
res = V_GetColorFromString(str, sc);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int V_GetColor(const uint32_t* palette, FScanner& sc)
|
||||
int V_GetColor(FScanner& sc)
|
||||
{
|
||||
FScriptPosition scc = sc;
|
||||
return V_GetColor(palette, sc.String, &scc);
|
||||
return V_GetColor(sc.String, &scc);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
struct FScriptPosition;
|
||||
class FScanner;
|
||||
|
||||
int BestColor(const uint32_t* pal, int r, int g, int b, int first = 1, int num = 255);
|
||||
int BestColor(const uint32_t* pal, int r, int g, int b, int first = 1, int num = 255, const uint8_t* indexmap = nullptr);
|
||||
int PTM_BestColor(const uint32_t* pal_in, int r, int g, int b, bool reverselookup, float powtable, int first = 1, int num = 255);
|
||||
void DoBlending(const PalEntry* from, PalEntry* to, int count, int r, int g, int b, int a);
|
||||
|
||||
|
@ -22,14 +22,14 @@ void HSVtoRGB (float *r, float *g, float *b, float h, float s, float v);
|
|||
|
||||
// Returns the closest color to the one desired. String
|
||||
// should be of the form "rr gg bb".
|
||||
int V_GetColorFromString(const uint32_t* palette, const char* colorstring, FScriptPosition* sc = nullptr);
|
||||
int V_GetColorFromString(const char* colorstring, FScriptPosition* sc = nullptr);
|
||||
// Scans through the X11R6RGB lump for a matching color
|
||||
// and returns a color string suitable for V_GetColorFromString.
|
||||
FString V_GetColorStringByName(const char* name, FScriptPosition* sc = nullptr);
|
||||
|
||||
// Tries to get color by name, then by string
|
||||
int V_GetColor(const uint32_t* palette, const char* str, FScriptPosition* sc = nullptr);
|
||||
int V_GetColor(const uint32_t* palette, FScanner& sc);
|
||||
int V_GetColor(const char* str, FScriptPosition* sc = nullptr);
|
||||
int V_GetColor(FScanner& sc);
|
||||
PalEntry averageColor(const uint32_t* data, int size, int maxout);
|
||||
|
||||
enum
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
// Simple lightweight reference counting pointer alternative for std::shared_ptr which stores the reference counter in the handled object itself.
|
||||
|
||||
// Base class for handled objects
|
||||
|
||||
// Base classes for handled objects
|
||||
class NoVirtualRefCountedBase
|
||||
{
|
||||
public:
|
||||
void IncRef() { refCount++; }
|
||||
void DecRef() { if (--refCount <= 0) delete this; }
|
||||
private:
|
||||
int refCount = 0;
|
||||
};
|
||||
|
||||
class RefCountedBase
|
||||
{
|
||||
public:
|
||||
void IncRef() { refCount++; }
|
||||
void DecRef() { if (--refCount <= 0) delete this; }
|
||||
void IncRef() { refCount++; }
|
||||
void DecRef() { if (--refCount <= 0) delete this; }
|
||||
private:
|
||||
int refCount = 0;
|
||||
int refCount = 0;
|
||||
protected:
|
||||
virtual ~RefCountedBase() = default;
|
||||
virtual ~RefCountedBase() = default;
|
||||
};
|
||||
|
||||
// The actual pointer object
|
||||
|
||||
// The actual pointer object
|
||||
template<class T>
|
||||
class RefCountedPtr
|
||||
{
|
||||
|
@ -31,10 +40,20 @@ public:
|
|||
{
|
||||
if (ptr) ptr->IncRef();
|
||||
}
|
||||
|
||||
|
||||
RefCountedPtr(const RefCountedPtr& r) : ptr(r.ptr)
|
||||
{
|
||||
if (ptr) ptr->IncRef();
|
||||
}
|
||||
|
||||
RefCountedPtr(RefCountedPtr&& r) : ptr(r.ptr)
|
||||
{
|
||||
r.ptr = nullptr;
|
||||
}
|
||||
|
||||
RefCountedPtr & operator=(const RefCountedPtr& r)
|
||||
{
|
||||
if (ptr != r.ptr)
|
||||
if (this != &r)
|
||||
{
|
||||
if (ptr) ptr->DecRef();
|
||||
ptr = r.ptr;
|
||||
|
@ -54,11 +73,14 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
RefCountedPtr & operator=(const RefCountedPtr&& r)
|
||||
RefCountedPtr & operator=(RefCountedPtr&& r)
|
||||
{
|
||||
if (ptr) ptr->DecRef();
|
||||
ptr = r.ptr;
|
||||
r.ptr = nullptr;
|
||||
if (this != &r)
|
||||
{
|
||||
if (ptr) ptr->DecRef();
|
||||
ptr = r.ptr;
|
||||
r.ptr = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ bool FPlayList::ChangeList (const char *path)
|
|||
}
|
||||
|
||||
// Check for relative paths.
|
||||
long slashpos = song.IndexOf('/');
|
||||
auto slashpos = song.IndexOf('/');
|
||||
|
||||
if (slashpos == 0)
|
||||
{
|
||||
|
|
|
@ -292,6 +292,17 @@ public:
|
|||
return i;
|
||||
}
|
||||
|
||||
bool Contains(const T& item) const
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0;i < Count;++i)
|
||||
{
|
||||
if(Array[i] == item)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class Func>
|
||||
unsigned int FindEx(Func compare) const
|
||||
{
|
||||
|
|
|
@ -422,7 +422,7 @@ void FString::Remove(size_t index, size_t remlen)
|
|||
{
|
||||
if (index + remlen >= Len())
|
||||
{
|
||||
Truncate((long)index);
|
||||
Truncate(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -500,12 +500,12 @@ void FString::DeleteLastCharacter()
|
|||
}
|
||||
|
||||
|
||||
long FString::IndexOf (const FString &substr, long startIndex) const
|
||||
ptrdiff_t FString::IndexOf (const FString &substr, ptrdiff_t startIndex) const
|
||||
{
|
||||
return IndexOf (substr.Chars, startIndex);
|
||||
}
|
||||
|
||||
long FString::IndexOf (const char *substr, long startIndex) const
|
||||
ptrdiff_t FString::IndexOf (const char *substr, ptrdiff_t startIndex) const
|
||||
{
|
||||
if (startIndex > 0 && Len() <= (size_t)startIndex)
|
||||
{
|
||||
|
@ -516,10 +516,10 @@ long FString::IndexOf (const char *substr, long startIndex) const
|
|||
{
|
||||
return -1;
|
||||
}
|
||||
return long(str - Chars);
|
||||
return str - Chars;
|
||||
}
|
||||
|
||||
long FString::IndexOf (char subchar, long startIndex) const
|
||||
ptrdiff_t FString::IndexOf (char subchar, ptrdiff_t startIndex) const
|
||||
{
|
||||
if (startIndex > 0 && Len() <= (size_t)startIndex)
|
||||
{
|
||||
|
@ -530,15 +530,15 @@ long FString::IndexOf (char subchar, long startIndex) const
|
|||
{
|
||||
return -1;
|
||||
}
|
||||
return long(str - Chars);
|
||||
return str - Chars;
|
||||
}
|
||||
|
||||
long FString::IndexOfAny (const FString &charset, long startIndex) const
|
||||
ptrdiff_t FString::IndexOfAny (const FString &charset, ptrdiff_t startIndex) const
|
||||
{
|
||||
return IndexOfAny (charset.Chars, startIndex);
|
||||
}
|
||||
|
||||
long FString::IndexOfAny (const char *charset, long startIndex) const
|
||||
ptrdiff_t FString::IndexOfAny (const char *charset, ptrdiff_t startIndex) const
|
||||
{
|
||||
if (startIndex > 0 && Len() <= (size_t)startIndex)
|
||||
{
|
||||
|
@ -549,19 +549,19 @@ long FString::IndexOfAny (const char *charset, long startIndex) const
|
|||
{
|
||||
return -1;
|
||||
}
|
||||
return long(brk - Chars);
|
||||
return brk - Chars;
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (char subchar) const
|
||||
ptrdiff_t FString::LastIndexOf (char subchar) const
|
||||
{
|
||||
return LastIndexOf (subchar, long(Len()));
|
||||
return LastIndexOf (subchar, Len());
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (char subchar, long endIndex) const
|
||||
ptrdiff_t FString::LastIndexOf (char subchar, ptrdiff_t endIndex) const
|
||||
{
|
||||
if ((size_t)endIndex > Len())
|
||||
{
|
||||
endIndex = long(Len());
|
||||
endIndex = Len();
|
||||
}
|
||||
while (--endIndex >= 0)
|
||||
{
|
||||
|
@ -573,16 +573,16 @@ long FString::LastIndexOf (char subchar, long endIndex) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
long FString::LastIndexOfBroken (const FString &_substr, long endIndex) const
|
||||
ptrdiff_t FString::LastIndexOfBroken (const FString &_substr, ptrdiff_t endIndex) const
|
||||
{
|
||||
const char *substr = _substr.GetChars();
|
||||
size_t substrlen = _substr.Len();
|
||||
if ((size_t)endIndex > Len())
|
||||
{
|
||||
endIndex = long(Len());
|
||||
endIndex = Len();
|
||||
}
|
||||
substrlen--;
|
||||
while (--endIndex >= long(substrlen))
|
||||
while (--endIndex >= ptrdiff_t(substrlen))
|
||||
{
|
||||
if (strncmp (substr, Chars + endIndex - substrlen, substrlen + 1) == 0)
|
||||
{
|
||||
|
@ -592,26 +592,26 @@ long FString::LastIndexOfBroken (const FString &_substr, long endIndex) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
long FString::LastIndexOfAny (const FString &charset) const
|
||||
ptrdiff_t FString::LastIndexOfAny (const FString &charset) const
|
||||
{
|
||||
return LastIndexOfAny (charset.Chars, long(Len()));
|
||||
return LastIndexOfAny (charset.Chars, Len());
|
||||
}
|
||||
|
||||
long FString::LastIndexOfAny (const char *charset) const
|
||||
ptrdiff_t FString::LastIndexOfAny (const char *charset) const
|
||||
{
|
||||
return LastIndexOfAny (charset, long(Len()));
|
||||
}
|
||||
|
||||
long FString::LastIndexOfAny (const FString &charset, long endIndex) const
|
||||
ptrdiff_t FString::LastIndexOfAny (const FString &charset, ptrdiff_t endIndex) const
|
||||
{
|
||||
return LastIndexOfAny (charset.Chars, endIndex);
|
||||
}
|
||||
|
||||
long FString::LastIndexOfAny (const char *charset, long endIndex) const
|
||||
ptrdiff_t FString::LastIndexOfAny (const char *charset, ptrdiff_t endIndex) const
|
||||
{
|
||||
if ((size_t)endIndex > Len())
|
||||
{
|
||||
endIndex = long(Len());
|
||||
endIndex = Len();
|
||||
}
|
||||
while (--endIndex >= 0)
|
||||
{
|
||||
|
@ -623,31 +623,31 @@ long FString::LastIndexOfAny (const char *charset, long endIndex) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const FString &substr) const
|
||||
ptrdiff_t FString::LastIndexOf (const FString &substr) const
|
||||
{
|
||||
return LastIndexOf(substr.Chars, long(Len() - substr.Len()), substr.Len());
|
||||
return LastIndexOf(substr.Chars, Len() - substr.Len(), substr.Len());
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const FString &substr, long endIndex) const
|
||||
ptrdiff_t FString::LastIndexOf (const FString &substr, ptrdiff_t endIndex) const
|
||||
{
|
||||
return LastIndexOf(substr.Chars, endIndex, substr.Len());
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const char *substr) const
|
||||
ptrdiff_t FString::LastIndexOf (const char *substr) const
|
||||
{
|
||||
return LastIndexOf(substr, long(Len() - strlen(substr)), strlen(substr));
|
||||
return LastIndexOf(substr, Len() - strlen(substr), strlen(substr));
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const char *substr, long endIndex) const
|
||||
ptrdiff_t FString::LastIndexOf (const char *substr, ptrdiff_t endIndex) const
|
||||
{
|
||||
return LastIndexOf(substr, endIndex, strlen(substr));
|
||||
}
|
||||
|
||||
long FString::LastIndexOf (const char *substr, long endIndex, size_t substrlen) const
|
||||
ptrdiff_t FString::LastIndexOf (const char *substr, ptrdiff_t endIndex, size_t substrlen) const
|
||||
{
|
||||
if ((size_t)endIndex + substrlen > Len())
|
||||
{
|
||||
endIndex = long(Len() - substrlen);
|
||||
endIndex = Len() - substrlen;
|
||||
}
|
||||
while (endIndex >= 0)
|
||||
{
|
||||
|
@ -1256,15 +1256,15 @@ void FString::Split(TArray<FString>& tokens, const char *delimiter, EmptyTokenTy
|
|||
{
|
||||
assert(nullptr != delimiter);
|
||||
|
||||
const long selfLen = static_cast<long>(Len());
|
||||
const long delimLen = static_cast<long>(strlen(delimiter));
|
||||
long lastPos = 0;
|
||||
const auto selfLen = static_cast<ptrdiff_t>(Len());
|
||||
const auto delimLen = static_cast<ptrdiff_t>(strlen(delimiter));
|
||||
ptrdiff_t lastPos = 0;
|
||||
|
||||
if (selfLen == 0) return; // Empty strings do not contain tokens, even with TOK_KEEPEMPTY.
|
||||
|
||||
while (lastPos <= selfLen)
|
||||
{
|
||||
long pos = IndexOf(delimiter, lastPos);
|
||||
auto pos = IndexOf(delimiter, lastPos);
|
||||
|
||||
if (-1 == pos)
|
||||
{
|
||||
|
|
|
@ -215,28 +215,28 @@ public:
|
|||
void AppendCharacter(int codepoint);
|
||||
void DeleteLastCharacter();
|
||||
|
||||
long IndexOf (const FString &substr, long startIndex=0) const;
|
||||
long IndexOf (const char *substr, long startIndex=0) const;
|
||||
long IndexOf (char subchar, long startIndex=0) const;
|
||||
ptrdiff_t IndexOf (const FString &substr, ptrdiff_t startIndex=0) const;
|
||||
ptrdiff_t IndexOf (const char *substr, ptrdiff_t startIndex=0) const;
|
||||
ptrdiff_t IndexOf (char subchar, ptrdiff_t startIndex=0) const;
|
||||
|
||||
long IndexOfAny (const FString &charset, long startIndex=0) const;
|
||||
long IndexOfAny (const char *charset, long startIndex=0) const;
|
||||
ptrdiff_t IndexOfAny (const FString &charset, ptrdiff_t startIndex=0) const;
|
||||
ptrdiff_t IndexOfAny (const char *charset, ptrdiff_t startIndex=0) const;
|
||||
|
||||
// This is only kept for backwards compatibility with old ZScript versions that used this function and depend on its bug.
|
||||
long LastIndexOf (char subchar) const;
|
||||
long LastIndexOfBroken (const FString &substr, long endIndex) const;
|
||||
long LastIndexOf (char subchar, long endIndex) const;
|
||||
ptrdiff_t LastIndexOf (char subchar) const;
|
||||
ptrdiff_t LastIndexOfBroken (const FString &substr, ptrdiff_t endIndex) const;
|
||||
ptrdiff_t LastIndexOf (char subchar, ptrdiff_t endIndex) const;
|
||||
|
||||
long LastIndexOfAny (const FString &charset) const;
|
||||
long LastIndexOfAny (const char *charset) const;
|
||||
long LastIndexOfAny (const FString &charset, long endIndex) const;
|
||||
long LastIndexOfAny (const char *charset, long endIndex) const;
|
||||
ptrdiff_t LastIndexOfAny (const FString &charset) const;
|
||||
ptrdiff_t LastIndexOfAny (const char *charset) const;
|
||||
ptrdiff_t LastIndexOfAny (const FString &charset, ptrdiff_t endIndex) const;
|
||||
ptrdiff_t LastIndexOfAny (const char *charset, ptrdiff_t endIndex) const;
|
||||
|
||||
long LastIndexOf (const FString &substr) const;
|
||||
long LastIndexOf (const FString &substr, long endIndex) const;
|
||||
long LastIndexOf (const char *substr) const;
|
||||
long LastIndexOf (const char *substr, long endIndex) const;
|
||||
long LastIndexOf (const char *substr, long endIndex, size_t substrlen) const;
|
||||
ptrdiff_t LastIndexOf (const FString &substr) const;
|
||||
ptrdiff_t LastIndexOf (const FString &substr, ptrdiff_t endIndex) const;
|
||||
ptrdiff_t LastIndexOf (const char *substr) const;
|
||||
ptrdiff_t LastIndexOf (const char *substr, ptrdiff_t endIndex) const;
|
||||
ptrdiff_t LastIndexOf (const char *substr, ptrdiff_t endIndex, size_t substrlen) const;
|
||||
|
||||
void ToUpper ();
|
||||
void ToLower ();
|
||||
|
|
|
@ -69,10 +69,10 @@ static bool CheatAddKey (cheatseq_t *cheat, uint8_t key, bool *eat)
|
|||
cheat->Pos = cheat->Sequence;
|
||||
cheat->CurrentArg = 0;
|
||||
}
|
||||
if (*cheat->Pos == '#' && key >= '0' && key <= '9')
|
||||
if (*cheat->Pos == '#' && ((key >= '0' && key <= '9') || key == ' '))
|
||||
{
|
||||
*eat = true;
|
||||
cheat->Args[cheat->CurrentArg++] = key;
|
||||
cheat->Args[cheat->CurrentArg++] = key == ' ' ? '0' : key;
|
||||
cheat->Pos++;
|
||||
}
|
||||
else if (upperforlower[key] == upperforlower[*cheat->Pos])
|
||||
|
|
|
@ -212,6 +212,7 @@ void CompleteLevel(MapRecord* map)
|
|||
gameaction = ga_completed;
|
||||
g_nextmap = !currentLevel || !(currentLevel->flags & MI_FORCEEOG)? map : nullptr;
|
||||
g_nextskill = -1; // This does not change the skill
|
||||
g_bossexit = false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -223,6 +224,7 @@ void CompleteLevel(MapRecord* map)
|
|||
void changeMap(int player, uint8_t** stream, bool skip)
|
||||
{
|
||||
int skill = (int8_t)ReadByte(stream);
|
||||
int bossexit = (int8_t)ReadByte(stream);
|
||||
auto mapname = ReadStringConst(stream);
|
||||
if (skip) return;
|
||||
auto map = FindMapByName(mapname);
|
||||
|
@ -231,6 +233,7 @@ void changeMap(int player, uint8_t** stream, bool skip)
|
|||
gameaction = ga_completed;
|
||||
g_nextmap = map;
|
||||
g_nextskill = skill;
|
||||
g_bossexit = bossexit;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,10 +254,11 @@ void endScreenJob(int player, uint8_t** stream, bool skip)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void ChangeLevel(MapRecord* map, int skill)
|
||||
void ChangeLevel(MapRecord* map, int skill, bool bossexit)
|
||||
{
|
||||
Net_WriteByte(DEM_CHANGEMAP);
|
||||
Net_WriteByte(skill);
|
||||
Net_WriteByte(bossexit);
|
||||
Net_WriteString(map? map->labelName : nullptr);
|
||||
}
|
||||
|
||||
|
@ -264,10 +268,11 @@ void ChangeLevel(MapRecord* map, int skill)
|
|||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void DeferedStartGame(MapRecord* map, int skill, bool nostopsound)
|
||||
void DeferredStartGame(MapRecord* map, int skill, bool nostopsound)
|
||||
{
|
||||
g_nextmap = map;
|
||||
g_nextskill = skill;
|
||||
g_bossexit = false;
|
||||
gameaction = nostopsound? ga_newgamenostopsound : ga_newgame;
|
||||
}
|
||||
|
||||
|
@ -334,7 +339,7 @@ CCMD(levelwarp)
|
|||
auto map = levelwarp_common(argv, "levelwarp", "warp to");
|
||||
if (map)
|
||||
{
|
||||
ChangeLevel(map, -1);
|
||||
ChangeLevel(map, g_nextskill);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +360,7 @@ CCMD(levelstart)
|
|||
auto map = levelwarp_common(argv, "start game", "start new game at");
|
||||
if (map)
|
||||
{
|
||||
DeferedStartGame(map, -1);
|
||||
DeferredStartGame(map, g_nextskill);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,7 +410,7 @@ CCMD(changemap)
|
|||
Printf(PRINT_BOLD, "%s: map file not found\n", map->fileName.GetChars());
|
||||
}
|
||||
|
||||
ChangeLevel(map, -1);
|
||||
ChangeLevel(map, g_nextskill);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -445,7 +450,7 @@ CCMD(map)
|
|||
Printf(PRINT_BOLD, "%s: map file not found\n", map->fileName.GetChars());
|
||||
}
|
||||
|
||||
DeferedStartGame(map, -1);
|
||||
DeferredStartGame(map, g_nextskill);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,7 +467,7 @@ CCMD(restartmap)
|
|||
Printf("Must be in a game to restart a level.\n");
|
||||
return;
|
||||
}
|
||||
ChangeLevel(currentLevel, -1);
|
||||
ChangeLevel(currentLevel, g_nextskill);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -493,5 +498,61 @@ CUSTOM_CVAR(Float, i_timescale, 1.0f, CVAR_NOINITCALL)
|
|||
CCMD(endofgame)
|
||||
{
|
||||
STAT_Update(true);
|
||||
ChangeLevel(nullptr, -1);
|
||||
ChangeLevel(nullptr, g_nextskill);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CCMD(skill)
|
||||
{
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
auto argsCount = argv.argc();
|
||||
|
||||
if (argsCount < 2)
|
||||
{
|
||||
auto currentSkill = gi->GetCurrentSkill();
|
||||
if (currentSkill >= 0)
|
||||
{
|
||||
Printf("Current skill is %d (%s)\n", currentSkill, GStrings.localize(gSkillNames[currentSkill]));
|
||||
}
|
||||
else if (currentSkill == -1)
|
||||
{
|
||||
Printf("Current skill is not set (%d)\n");
|
||||
}
|
||||
else if (currentSkill == -2)
|
||||
{
|
||||
Printf("This game has no skill settings.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Current skill is an unknown/unsupported value (%d)\n");
|
||||
}
|
||||
}
|
||||
else if (argsCount == 2)
|
||||
{
|
||||
auto newSkill = atoi(argv[1]);
|
||||
if (newSkill >= 0 and newSkill < MAXSKILLS)
|
||||
{
|
||||
g_nextskill = newSkill;
|
||||
Printf("Skill will be changed for next game.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Please specify a skill level between 0 and %d\n", MAXSKILLS - 1);
|
||||
}
|
||||
}
|
||||
else if (argsCount > 2)
|
||||
{
|
||||
Printf(PRINT_BOLD, "skill <newskill>: returns the current skill level, and optionally sets the skill level for the next game.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Currently not in a game.\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -326,7 +326,7 @@ static void ShoveChatStr (const char *str, uint8_t who)
|
|||
|
||||
if (*str == '#')
|
||||
{
|
||||
C_DoCommand(FStringf("activatecheat %s", str + 1));
|
||||
C_DoCommand(FStringf("activatecheat \"%s\"", str + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "buildtiles.h"
|
||||
#include "bitmap.h"
|
||||
#include "m_argv.h"
|
||||
#include "gamestruct.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "palettecontainer.h"
|
||||
#include "mapinfo.h"
|
||||
|
@ -2008,6 +2009,193 @@ void parseModel(FScanner& sc, FScriptPosition& pos)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static bool parseDefineQAVInterpolateIgnoreBlock(FScanner& sc, const int& res_id, TMap<int, TArray<int>>& ignoredata, const int& numframes)
|
||||
{
|
||||
FScanner::SavedPos blockend;
|
||||
FScriptPosition pos = sc;
|
||||
|
||||
FString scframes, sctiles;
|
||||
TArray<int> framearray, tilearray;
|
||||
|
||||
if (sc.StartBraces(&blockend))
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: malformed syntax, unable to continue", res_id);
|
||||
return false;
|
||||
}
|
||||
while (!sc.FoundEndBrace(blockend))
|
||||
{
|
||||
sc.GetString();
|
||||
if (sc.Compare("frames")) sc.GetString(scframes);
|
||||
else if (sc.Compare("tiles")) sc.GetString(sctiles);
|
||||
}
|
||||
|
||||
// Confirm we received something for 'frames' and 'tiles'.
|
||||
if (scframes.IsEmpty() || sctiles.IsEmpty())
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: unable to get any values for 'frames' or 'tiles', unable to continue", res_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto arraybuilder = [&](const FString& input, TArray<int>& output, const int& maxvalue) -> bool
|
||||
{
|
||||
if (input.CompareNoCase("all") == 0)
|
||||
{
|
||||
// All indices from 0 through to maxvalue are to be added to output array.
|
||||
output.Push(0);
|
||||
output.Push(maxvalue);
|
||||
}
|
||||
else if (input.IndexOf("-") != -1)
|
||||
{
|
||||
// Input is a range of values, split on the hypthen and add each value to the output array.
|
||||
auto temparray = input.Split("-");
|
||||
if (temparray.Size() == 2)
|
||||
{
|
||||
// Test if keywords 'first' and 'last' have been used.'
|
||||
output.Push(temparray[0].CompareNoCase("first") == 0 ? 0 : atoi(temparray[0]));
|
||||
output.Push(temparray[1].CompareNoCase("last") == 0 ? maxvalue : atoi(temparray[1]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We just have a number. Convert the string into an int and push it twice to the output array.
|
||||
auto tempvalue = atoi(input);
|
||||
for (auto i = 0; i < 2; i++) output.Push(tempvalue);
|
||||
}
|
||||
if (output.Size() != 2 || output[0] > output[1] || output[0] < 0 || output[1] > maxvalue)
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: ignore: value of '%s' is malformed, unable to continue", res_id, input.GetChars());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!arraybuilder(scframes, framearray, numframes - 1)) return false;
|
||||
if (!arraybuilder(sctiles, tilearray, 7)) return false;
|
||||
|
||||
// Process arrays and add ignored frames as required.
|
||||
for (auto i = framearray[0]; i <= framearray[1]; i++)
|
||||
{
|
||||
auto& frametiles = ignoredata[i];
|
||||
for (auto j = tilearray[0]; j <= tilearray[1]; j++)
|
||||
{
|
||||
if (!frametiles.Contains(j)) frametiles.Push(j);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parseDefineQAVInterpolateBlock(FScanner& sc, const int& res_id, const int& numframes)
|
||||
{
|
||||
FScanner::SavedPos blockend;
|
||||
FScriptPosition pos = sc;
|
||||
|
||||
FString interptype;
|
||||
bool loopable = false;
|
||||
TMap<int, TArray<int>> ignoredata;
|
||||
|
||||
if (sc.StartBraces(&blockend))
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): malformed syntax, unable to continue", res_id, interptype.GetChars());
|
||||
return false;
|
||||
}
|
||||
while (!sc.FoundEndBrace(blockend))
|
||||
{
|
||||
sc.GetString();
|
||||
if (sc.Compare("type"))
|
||||
{
|
||||
if (interptype.IsNotEmpty())
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): more than one interpolation type defined, unable to continue", res_id, interptype.GetChars());
|
||||
return false;
|
||||
}
|
||||
sc.GetString(interptype);
|
||||
if (!gi->IsQAVInterpTypeValid(interptype))
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): interpolation type not found", res_id, interptype.GetChars());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("loopable")) loopable = true;
|
||||
else if (sc.Compare("ignore")) if (!parseDefineQAVInterpolateIgnoreBlock(sc, res_id, ignoredata, numframes)) return false;
|
||||
}
|
||||
|
||||
// Add interpolation properties to game for processing while drawing.
|
||||
gi->AddQAVInterpProps(res_id, interptype, loopable, ignoredata);
|
||||
return true;
|
||||
}
|
||||
|
||||
void parseDefineQAV(FScanner& sc, FScriptPosition& pos)
|
||||
{
|
||||
FScanner::SavedPos blockend;
|
||||
FString fn;
|
||||
int res_id = -1;
|
||||
int numframes = -1;
|
||||
bool interpolate = false;
|
||||
|
||||
if (!sc.GetNumber(res_id, true))
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav: invalid or non-defined resource ID");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc.StartBraces(&blockend))
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): malformed syntax, unable to continue", res_id);
|
||||
return;
|
||||
}
|
||||
while (!sc.FoundEndBrace(blockend))
|
||||
{
|
||||
sc.MustGetString();
|
||||
if (sc.Compare("file"))
|
||||
{
|
||||
if (fn.IsNotEmpty())
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): more than one file defined, unable to continue", res_id);
|
||||
return;
|
||||
}
|
||||
sc.GetString(fn);
|
||||
|
||||
// Test file's validity.
|
||||
FixPathSeperator(fn);
|
||||
auto lump = fileSystem.FindFile(fn);
|
||||
if (lump < 0)
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): file '%s' could not be found", res_id, fn.GetChars());
|
||||
return;
|
||||
}
|
||||
|
||||
// Read file to get number of frames from QAV, skipping first 8 bytes.
|
||||
auto fr = fileSystem.OpenFileReader(lump);
|
||||
fr.ReadUInt64();
|
||||
numframes = fr.ReadInt32();
|
||||
}
|
||||
else if (sc.Compare("interpolate"))
|
||||
{
|
||||
if (interpolate)
|
||||
{
|
||||
pos.Message(MSG_ERROR, "defineqav (%d): more than one interpolate block defined, unable to continue", res_id);
|
||||
return;
|
||||
}
|
||||
interpolate = true;
|
||||
if (!parseDefineQAVInterpolateBlock(sc, res_id, numframes)) return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're not interpolating, remove any reference to interpolation data for this res_id.
|
||||
if (!interpolate) gi->RemoveQAVInterpProps(res_id);
|
||||
|
||||
// Add new file to filesystem.
|
||||
fileSystem.CreatePathlessCopy(fn, res_id, 0);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -2098,6 +2286,7 @@ static const dispatch basetokens[] =
|
|||
{ "shadefactor", parseSkip<1> },
|
||||
{ "newgamechoices", parseEmptyBlock },
|
||||
{ "rffdefineid", parseRffDefineId },
|
||||
{ "defineqav", parseDefineQAV },
|
||||
{ nullptr, nullptr },
|
||||
};
|
||||
|
||||
|
|
|
@ -408,7 +408,7 @@ DEFINE_MAP_OPTION(fade, true)
|
|||
{
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetString();
|
||||
info->fadeto = V_GetColor(nullptr, parse.sc);
|
||||
info->fadeto = V_GetColor(parse.sc);
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(partime, true)
|
||||
|
@ -645,9 +645,11 @@ MapFlagHandlers[] =
|
|||
{ "sw_bossmeter_sumo", MITYPE_SETFLAGG,LEVEL_SW_BOSSMETER_SUMO, 0, GAMEFLAG_SW },
|
||||
{ "sw_bossmeter_zilla", MITYPE_SETFLAGG,LEVEL_SW_BOSSMETER_ZILLA, 0, GAMEFLAG_SW },
|
||||
{ "sw_deathexit_serpent", MITYPE_SETFLAGG,LEVEL_SW_DEATHEXIT_SERPENT, 0, GAMEFLAG_SW },
|
||||
{ "sw_deathexit_serpent_next", MITYPE_SETFLAGG,LEVEL_SW_DEATHEXIT_SERPENT | LEVEL_SW_DEATHEXIT_SERPENT_NEXT, 0, GAMEFLAG_SW },
|
||||
{ "sw_deathexit_sumo", MITYPE_SETFLAGG,LEVEL_SW_DEATHEXIT_SUMO, 0, GAMEFLAG_SW },
|
||||
{ "sw_deathexit_zilla", MITYPE_SETFLAGG,LEVEL_SW_DEATHEXIT_ZILLA, 0, GAMEFLAG_SW },
|
||||
{ "sw_spawnmines", MITYPE_SETFLAGG,LEVEL_SW_SPAWNMINES, 0, GAMEFLAG_SW },
|
||||
{ "bossonlycutscene", MITYPE_SETFLAGG,LEVEL_BOSSONLYCUTSCENE, 0, -1 },
|
||||
|
||||
{ NULL, MITYPE_IGNORE, 0, 0}
|
||||
};
|
||||
|
|
|
@ -122,6 +122,7 @@ gameaction_t gameaction = ga_nothing;
|
|||
// gameaction state
|
||||
MapRecord* g_nextmap;
|
||||
int g_nextskill;
|
||||
int g_bossexit;
|
||||
|
||||
|
||||
FILE* hashfile;
|
||||
|
@ -343,7 +344,7 @@ void UserConfig::ProcessOptions()
|
|||
{
|
||||
gamegrp = "BLOOD.RFF";
|
||||
DefaultCon = "CRYPTIC.INI";
|
||||
const char* argv[] = { "cpart07.ar_" , "cpart15.ar_" };
|
||||
const char* argv[] = { "CPART07.AR_", "CPART15.AR_" };
|
||||
AddArt.reset(new FArgs(2, argv));
|
||||
}
|
||||
|
||||
|
@ -697,7 +698,7 @@ static TArray<GrpEntry> SetupGame()
|
|||
{
|
||||
auto grplower = grp.FileName.MakeLower();
|
||||
FixPathSeperator(grplower);
|
||||
int pos = grplower.LastIndexOf(gamegrplower);
|
||||
auto pos = grplower.LastIndexOf(gamegrplower);
|
||||
if (pos >= 0 && pos == grplower.Len() - gamegrplower.Len())
|
||||
{
|
||||
groupno = g;
|
||||
|
@ -903,6 +904,7 @@ static void InitTextures()
|
|||
lookups.postLoadLookups();
|
||||
SetupFontSubstitution();
|
||||
V_LoadTranslations(); // loading the translations must be delayed until the palettes have been fully set up.
|
||||
UpdateUpscaleMask();
|
||||
TileFiles.SetBackup();
|
||||
}
|
||||
|
||||
|
@ -912,6 +914,8 @@ static void InitTextures()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static uint8_t palindexmap[256];
|
||||
|
||||
int RunGame()
|
||||
{
|
||||
GameStartupInfo.FgColor = 0xffffff;
|
||||
|
@ -949,11 +953,11 @@ int RunGame()
|
|||
colorset = true;
|
||||
}
|
||||
}
|
||||
if (grp.FileInfo.mpepisodes.Size())
|
||||
if (grp.FileInfo.exclepisodes.Size())
|
||||
{
|
||||
for (auto& mpepisode : grp.FileInfo.mpepisodes)
|
||||
for (auto& episode : grp.FileInfo.exclepisodes)
|
||||
{
|
||||
gi->AddMultiplayerEpisode(mpepisode);
|
||||
gi->AddExcludedEpisode(episode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1021,7 +1025,11 @@ int RunGame()
|
|||
}
|
||||
GameTicRate = 30;
|
||||
CheckUserMap();
|
||||
GPalette.Init(MAXPALOOKUPS + 2); // one slot for each translation, plus a separate one for the base palettes and the internal one
|
||||
|
||||
palindexmap[0] = 255;
|
||||
for (int i = 1; i <= 255; i++) palindexmap[i] = i;
|
||||
GPalette.Init(MAXPALOOKUPS + 2, palindexmap); // one slot for each translation, plus a separate one for the base palettes and the internal one
|
||||
int v = ColorMatcher.Pick(0, 0, 0);
|
||||
gi->loadPalette();
|
||||
StartScreen->Progress();
|
||||
InitTextures();
|
||||
|
|
|
@ -32,6 +32,7 @@ extern bool crouch_toggle;
|
|||
struct MapRecord;
|
||||
extern MapRecord* g_nextmap;
|
||||
extern int g_nextskill;
|
||||
extern int g_bossexit;
|
||||
|
||||
extern FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown.
|
||||
|
||||
|
@ -43,8 +44,8 @@ int GetAutomapZoom(int gZoom);
|
|||
|
||||
void DrawCrosshair(int deftile, int health, double xdelta, double ydelta, double scale, PalEntry color = 0xffffffff);
|
||||
void updatePauseStatus();
|
||||
void DeferedStartGame(MapRecord* map, int skill, bool nostopsound = false);
|
||||
void ChangeLevel(MapRecord* map, int skill);
|
||||
void DeferredStartGame(MapRecord* map, int skill, bool nostopsound = false);
|
||||
void ChangeLevel(MapRecord* map, int skill, bool bossexit = false);
|
||||
void CompleteLevel(MapRecord* map);
|
||||
|
||||
struct UserConfig
|
||||
|
@ -132,7 +133,7 @@ struct GrpInfo
|
|||
TArray<FString> tobedeleted;
|
||||
TArray<FString> loadfiles;
|
||||
TArray<FString> loadart;
|
||||
TArray<FString> mpepisodes;
|
||||
TArray<FString> exclepisodes;
|
||||
uint32_t FgColor = 0, BgColor = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -76,12 +76,19 @@ CVARD(Bool, cl_interpolate, true, CVAR_ARCHIVE, "enable/disable view interpolati
|
|||
CVARD(Bool, cl_slopetilting, false, CVAR_ARCHIVE, "enable/disable slope tilting") // only implemented in Blood
|
||||
CVARD(Int, cl_showweapon, 1, CVAR_ARCHIVE, "enable/disable show weapons") // only implemented in Blood
|
||||
CVARD(Bool, cl_sointerpolation, true, CVAR_ARCHIVE, "enable/disable sector object interpolation") // only implemented in SW
|
||||
CVARD(Bool, cl_syncinput, false, CVAR_ARCHIVE, "enable/disable synchronized input with game's ticrate") // only implemented in Duke
|
||||
CVARD(Bool, cl_syncinput, false, CVAR_ARCHIVE, "enable/disable synchronized input with game's tickrate") // only implemented in Duke
|
||||
CVARD(Bool, cl_swsmoothsway, true, CVAR_ARCHIVE, "move SW weapon left and right smoothly while bobbing")
|
||||
CVARD(Bool, cl_showmagamt, false, CVAR_ARCHIVE, "show the amount of rounds left in the magazine of your weapon on the modern HUD")
|
||||
CVARD(Bool, cl_nomeleeblur, false, CVAR_ARCHIVE, "enable/disable blur effect with melee weapons in SW")
|
||||
CVARD(Bool, cl_exhumedoldturn, false, CVAR_ARCHIVE, "enable/disable legacy turning speed for Powerslave/Exhumed")
|
||||
CVARD(Bool, cl_hudinterpolation, true, CVAR_ARCHIVE, "enable/disable HUD (weapon drawer) interpolation")
|
||||
CVARD(Bool, cl_bloodvanillarun, true, CVAR_ARCHIVE, "enable/disable Blood's vanilla run mode")
|
||||
CVARD(Bool, cl_bloodvanillabobbing, true, CVAR_ARCHIVE, "enable/disable Blood's vanilla bobbing while not using vanilla run mode")
|
||||
CVARD(Bool, cl_bloodvanillaexplosions, false, CVAR_ARCHIVE, "enable/disable Blood's vanilla explosion behavior")
|
||||
CVARD(Bool, cl_bloodvanillaenemies, false, CVAR_ARCHIVE, "enable/disable Blood's vanilla enemy behavior")
|
||||
CVARD(Bool, cl_bloodqavinterp, true, CVAR_ARCHIVE, "enable/disable Blood's QAV interpolation")
|
||||
CVARD(Bool, cl_bloodweapinterp, false, CVAR_ARCHIVE, "enable/disable Blood's weapon interpolation. Depends on 'cl_bloodqavinterp'")
|
||||
CVARD(Bool, cl_bloodoldweapbalance, false, CVAR_ARCHIVE, "enable/disable legacy 1.0 weapon handling for Blood")
|
||||
|
||||
|
||||
CUSTOM_CVARD(Int, cl_autoaim, 1, CVAR_ARCHIVE|CVAR_USERINFO, "enable/disable weapon autoaim")
|
||||
|
|
|
@ -27,6 +27,13 @@ EXTERN_CVAR(Bool, cl_showmagamt)
|
|||
EXTERN_CVAR(Bool, cl_nomeleeblur)
|
||||
EXTERN_CVAR(Bool, cl_exhumedoldturn)
|
||||
EXTERN_CVAR(Bool, cl_hudinterpolation)
|
||||
EXTERN_CVAR(Bool, cl_bloodvanillarun)
|
||||
EXTERN_CVAR(Bool, cl_bloodvanillabobbing)
|
||||
EXTERN_CVAR(Bool, cl_bloodvanillaexplosions)
|
||||
EXTERN_CVAR(Bool, cl_bloodvanillaenemies)
|
||||
EXTERN_CVAR(Bool, cl_bloodqavinterp)
|
||||
EXTERN_CVAR(Bool, cl_bloodweapinterp)
|
||||
EXTERN_CVAR(Bool, cl_bloodoldweapbalance)
|
||||
|
||||
EXTERN_CVAR(Bool, demorec_seeds_cvar)
|
||||
EXTERN_CVAR(Bool, demoplay_diffs)
|
||||
|
|
|
@ -156,3 +156,8 @@ inline int spriteGetSlope(int spritenum)
|
|||
auto spr = &sprite[spritenum];
|
||||
return ((spr->cstat & CSTAT_SPRITE_ALIGNMENT_MASK) != CSTAT_SPRITE_ALIGNMENT_SLOPE) ? 0 : uint8_t(spr->xoffset) + (uint8_t(spr->yoffset) << 8);
|
||||
}
|
||||
|
||||
inline int I_GetBuildTime()
|
||||
{
|
||||
return I_GetTime(120);
|
||||
}
|
||||
|
|
|
@ -50,9 +50,9 @@
|
|||
F2DDrawer twodpsp;
|
||||
|
||||
|
||||
void hud_drawsprite(double sx, double sy, int z, double a, int picnum, int dashade, int dapalnum, int dastat, double alpha)
|
||||
void hud_drawsprite(double sx, double sy, double sz, double a, int picnum, int dashade, int dapalnum, int dastat, double alpha)
|
||||
{
|
||||
double dz = z / 65536.;
|
||||
sz *= 1. / 65536.;
|
||||
alpha *= (dastat & RS_TRANS1)? glblend[0].def[!!(dastat & RS_TRANS2)].alpha : 1.;
|
||||
int palid = TRANSLATION(Translation_Remap + curbasepal, dapalnum);
|
||||
|
||||
|
@ -62,7 +62,7 @@ void hud_drawsprite(double sx, double sy, int z, double a, int picnum, int dasha
|
|||
auto tex = tileGetTexture(picnum);
|
||||
|
||||
DrawTexture(&twodpsp, tex, sx, sy,
|
||||
DTA_ScaleX, dz, DTA_ScaleY, dz,
|
||||
DTA_ScaleX, sz, DTA_ScaleY, sz,
|
||||
DTA_Color, shadeToLight(dashade),
|
||||
DTA_TranslationIndex, palid,
|
||||
DTA_ViewportX, windowxy1.x, DTA_ViewportY, windowxy1.y,
|
||||
|
@ -107,7 +107,9 @@ static FString statFPS()
|
|||
frameCount++;
|
||||
if (frameDelay >= 0)
|
||||
{
|
||||
output.AppendFormat("%5.1f fps (%.1f ms)\n", lastFPS, frameDelay);
|
||||
output.AppendFormat("%5.1f fps", lastFPS);
|
||||
if (frameDelay < 10) output.AppendFormat(" ");
|
||||
output.AppendFormat(" (%.1f ms)\n", frameDelay);
|
||||
|
||||
if (cumulativeFrameDelay >= 1000.0)
|
||||
{
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
extern F2DDrawer twodpsp;
|
||||
|
||||
void DrawRateStuff();
|
||||
void hud_drawsprite(double sx, double sy, int z, double a, int picnum, int dashade, int dapalnum, int dastat, double alpha = 1);
|
||||
void hud_drawsprite(double sx, double sy, double sz, double a, int picnum, int dashade, int dapalnum, int dastat, double alpha = 1);
|
||||
|
|
|
@ -246,8 +246,8 @@ void processMovement(InputPacket* currInput, InputPacket* inputBuffer, ControlIn
|
|||
|
||||
void PlayerHorizon::applyinput(float const horz, ESyncBits* actions, double const scaleAdjust)
|
||||
{
|
||||
// Process only if no targeted horizon set.
|
||||
if (!targetset())
|
||||
// Process only if movewment isn't locked.
|
||||
if (!movementlocked())
|
||||
{
|
||||
// Store current horizon as true pitch.
|
||||
double pitch = horiz.aspitch();
|
||||
|
@ -342,7 +342,7 @@ void PlayerAngle::applyinput(float const avel, ESyncBits* actions, double const
|
|||
rotscrnang += buildfang(scaleAdjust * -(720. / GameTicRate));
|
||||
}
|
||||
|
||||
if (!targetset())
|
||||
if (!movementlocked())
|
||||
{
|
||||
if (*actions & SB_TURNAROUND)
|
||||
{
|
||||
|
@ -450,6 +450,7 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, PlayerAngle& w, Pl
|
|||
("lookang", w.look_ang)
|
||||
("rotscrnang", w.rotscrnang)
|
||||
("spin", w.spin)
|
||||
("inputdisabled", w.inputdisabled)
|
||||
.EndObject();
|
||||
|
||||
if (arc.isReading())
|
||||
|
@ -457,6 +458,7 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, PlayerAngle& w, Pl
|
|||
w.oang = w.ang;
|
||||
w.olook_ang = w.look_ang;
|
||||
w.orotscrnang = w.rotscrnang;
|
||||
w.inputdisabled = w.inputdisabled;
|
||||
w.resetadjustment();
|
||||
}
|
||||
}
|
||||
|
@ -469,12 +471,14 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, PlayerHorizon& w,
|
|||
{
|
||||
arc("horiz", w.horiz)
|
||||
("horizoff", w.horizoff)
|
||||
("inputdisabled", w.inputdisabled)
|
||||
.EndObject();
|
||||
|
||||
if (arc.isReading())
|
||||
{
|
||||
w.ohoriz = w.horiz;
|
||||
w.ohorizoff = w.horizoff;
|
||||
w.inputdisabled = w.inputdisabled;
|
||||
w.resetadjustment();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ struct PlayerHorizon
|
|||
{
|
||||
fixedhoriz horiz, ohoriz, horizoff, ohorizoff;
|
||||
|
||||
friend FSerializer& Serialize(FSerializer& arc, const char* keyname, PlayerHorizon& w, PlayerHorizon* def);
|
||||
|
||||
void backup()
|
||||
{
|
||||
ohoriz = horiz;
|
||||
|
@ -50,11 +52,26 @@ struct PlayerHorizon
|
|||
__settarget(value, backup);
|
||||
}
|
||||
|
||||
void lockinput()
|
||||
{
|
||||
inputdisabled = true;
|
||||
}
|
||||
|
||||
void unlockinput()
|
||||
{
|
||||
inputdisabled = false;
|
||||
}
|
||||
|
||||
bool targetset()
|
||||
{
|
||||
return target.asq16();
|
||||
}
|
||||
|
||||
bool movementlocked()
|
||||
{
|
||||
return target.asq16() || inputdisabled;
|
||||
}
|
||||
|
||||
void processhelpers(double const scaleAdjust)
|
||||
{
|
||||
if (targetset())
|
||||
|
@ -103,6 +120,7 @@ struct PlayerHorizon
|
|||
private:
|
||||
fixedhoriz target;
|
||||
double adjustment;
|
||||
bool inputdisabled;
|
||||
|
||||
void __addadjustment(fixedhoriz value)
|
||||
{
|
||||
|
@ -138,6 +156,8 @@ struct PlayerAngle
|
|||
binangle ang, oang, look_ang, olook_ang, rotscrnang, orotscrnang;
|
||||
double spin;
|
||||
|
||||
friend FSerializer& Serialize(FSerializer& arc, const char* keyname, PlayerAngle& w, PlayerAngle* def);
|
||||
|
||||
void backup()
|
||||
{
|
||||
oang = ang;
|
||||
|
@ -177,11 +197,26 @@ struct PlayerAngle
|
|||
__settarget(value, backup);
|
||||
}
|
||||
|
||||
void lockinput()
|
||||
{
|
||||
inputdisabled = true;
|
||||
}
|
||||
|
||||
void unlockinput()
|
||||
{
|
||||
inputdisabled = false;
|
||||
}
|
||||
|
||||
bool targetset()
|
||||
{
|
||||
return target.asbam();
|
||||
}
|
||||
|
||||
bool movementlocked()
|
||||
{
|
||||
return target.asq16() || inputdisabled;
|
||||
}
|
||||
|
||||
void processhelpers(double const scaleAdjust)
|
||||
{
|
||||
if (targetset())
|
||||
|
@ -244,6 +279,7 @@ struct PlayerAngle
|
|||
private:
|
||||
binangle target;
|
||||
double adjustment;
|
||||
bool inputdisabled;
|
||||
|
||||
void __addadjustment(binangle value)
|
||||
{
|
||||
|
|
|
@ -120,7 +120,11 @@ struct GameInterface
|
|||
virtual void LeavePortal(spritetype* viewer, int type) {}
|
||||
virtual bool GetGeoEffect(GeoEffect* eff, int viewsector) { return false; }
|
||||
virtual int Voxelize(int sprnum) { return -1; }
|
||||
virtual void AddMultiplayerEpisode(FString name) {}
|
||||
virtual void AddExcludedEpisode(FString episode) {}
|
||||
virtual int GetCurrentSkill() { return -1; }
|
||||
virtual bool IsQAVInterpTypeValid(const FString& type) { return false; }
|
||||
virtual void AddQAVInterpProps(const int& res_id, const FString& interptype, const bool& loopable, const TMap<int, TArray<int>>& ignoredata) { }
|
||||
virtual void RemoveQAVInterpProps(const int& res_id) { }
|
||||
|
||||
virtual FString statFPS()
|
||||
{
|
||||
|
|
|
@ -117,10 +117,10 @@ static TArray<FString> ParseGameInfo(TArray<FString>& pwads, const char* fn, con
|
|||
else if (!nextKey.CompareNoCase("STARTUPCOLORS"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
GameStartupInfo.FgColor = V_GetColor(NULL, sc);
|
||||
GameStartupInfo.FgColor = V_GetColor(sc);
|
||||
sc.MustGetStringName(",");
|
||||
sc.MustGetString();
|
||||
GameStartupInfo.BkColor = V_GetColor(NULL, sc);
|
||||
GameStartupInfo.BkColor = V_GetColor(sc);
|
||||
}
|
||||
else if (!nextKey.CompareNoCase("CON"))
|
||||
{
|
||||
|
|
|
@ -688,7 +688,7 @@ void MainLoop ()
|
|||
userConfig.CommandMap = "";
|
||||
if (maprecord)
|
||||
{
|
||||
DeferedStartGame(maprecord, -1);
|
||||
DeferredStartGame(maprecord, g_nextskill);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "c_dispatch.h"
|
||||
#include "md4.h"
|
||||
#include "hw_sections.h"
|
||||
#include "mapinfo.h"
|
||||
|
||||
static TArray<usermaphack_t> usermaphacks;
|
||||
TArray<int> blockingpairs[MAXWALLS];
|
||||
|
@ -249,6 +250,10 @@ static int32_t LoadMapHack(const char *filename)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (sc.Compare("sw_serp_continue")) // This is a hack for SW's Last Warrior mod to continue from L4 to L5.
|
||||
{
|
||||
currentLevel->gameflags |= LEVEL_SW_DEATHEXIT_SERPENT_NEXT;
|
||||
}
|
||||
|
||||
else if (sc.Compare("angleoff") || sc.Compare("angoff"))
|
||||
{
|
||||
|
|
|
@ -71,6 +71,7 @@ CCMD(listmaps)
|
|||
|
||||
MapRecord *FindMapByName(const char *nm)
|
||||
{
|
||||
if (!nm || !*nm) return nullptr;
|
||||
for (auto& map : mapList)
|
||||
{
|
||||
if (map->labelName.CompareNoCase(nm) == 0)
|
||||
|
|
|
@ -51,10 +51,11 @@ enum EMapGameFlags
|
|||
LEVEL_SW_DEATHEXIT_SERPENT = 1024,
|
||||
LEVEL_SW_DEATHEXIT_SUMO = 2048,
|
||||
LEVEL_SW_DEATHEXIT_ZILLA = 4096,
|
||||
LEVEL_SW_DEATHEXIT_SERPENT_NEXT = 8192,
|
||||
|
||||
LEVEL_WT_BOSSSPAWN = 8192,
|
||||
|
||||
LEVEL_WT_BOSSSPAWN = 16384,
|
||||
|
||||
LEVEL_BOSSONLYCUTSCENE = 32768,
|
||||
};
|
||||
|
||||
// These get filled in by the map definition parsers of the front ends.
|
||||
|
|
|
@ -493,4 +493,18 @@ void setWallSectors()
|
|||
wall[sector[i].wallptr + w].sector = i;
|
||||
}
|
||||
}
|
||||
|
||||
// validate 'nextsector' fields. Some maps have these wrong which can cause render glitches and occasionally even crashes.
|
||||
for (int i = 0; i < numwalls; i++)
|
||||
{
|
||||
if (wall[i].nextwall != -1)
|
||||
{
|
||||
if (wall[i].nextsector != wall[wall[i].nextwall].sector)
|
||||
{
|
||||
DPrintf(DMSG_ERROR, "Bad 'nextsector' reference %d on wall %d\n", wall[i].nextsector, i);
|
||||
wall[i].nextsector = wall[wall[i].nextwall].sector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -105,7 +105,7 @@ static bool DoStartGame(FNewGameStartup& gs)
|
|||
|
||||
gi->StartGame(gs); // play game specific effects (like Duke/RR/SW's voice lines when starting a game.)
|
||||
|
||||
DeferedStartGame(map, gs.Skill);
|
||||
DeferredStartGame(map, gs.Skill);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -187,6 +187,9 @@ void ShowScoreboard(int numplayers, const CompletionFunc& completion_)
|
|||
|
||||
void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, CompletionFunc completion_)
|
||||
{
|
||||
bool bossexit = g_bossexit;
|
||||
g_bossexit = false;
|
||||
|
||||
completion = completion_;
|
||||
runner = CreateRunner();
|
||||
GC::WriteBarrier(runner);
|
||||
|
@ -200,7 +203,7 @@ void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, C
|
|||
|
||||
try
|
||||
{
|
||||
if (fromMap)
|
||||
if (fromMap && (!(fromMap->gameflags & LEVEL_BOSSONLYCUTSCENE) || bossexit))
|
||||
{
|
||||
if (!CreateCutscene(&fromMap->outro, runner, fromMap, !!toMap))
|
||||
{
|
||||
|
@ -212,7 +215,7 @@ void ShowIntermission(MapRecord* fromMap, MapRecord* toMap, SummaryInfo* info, C
|
|||
if (fromMap || (g_gameType & GAMEFLAG_PSEXHUMED))
|
||||
CallCreateSummaryFunction(globalCutscenes.SummaryScreen, runner, fromMap, info, toMap);
|
||||
|
||||
if (toMap)
|
||||
if (toMap)
|
||||
{
|
||||
if (!CreateCutscene(&toMap->intro, runner, toMap, !!fromMap))
|
||||
{
|
||||
|
|
|
@ -588,12 +588,12 @@ static TArray<GrpInfo> ParseGrpInfo(const char *fn, FileReader &fr, TMap<FString
|
|||
}
|
||||
while (sc.CheckToken(','));
|
||||
}
|
||||
else if (sc.Compare("mpepisodes"))
|
||||
else if (sc.Compare("exclepisodes"))
|
||||
{
|
||||
do
|
||||
{
|
||||
sc.MustGetToken(TK_StringConst);
|
||||
grp.mpepisodes.Push(sc.String);
|
||||
grp.exclepisodes.Push(sc.String);
|
||||
}
|
||||
while (sc.CheckToken(','));
|
||||
}
|
||||
|
|
|
@ -463,9 +463,9 @@ bool SectorGeometry::MakeVertices2(unsigned int secnum, int plane, const FVector
|
|||
nexti:;
|
||||
}
|
||||
|
||||
if (lines.Size() == 0)
|
||||
if (lines.Size() < 4)
|
||||
{
|
||||
// nothing to generate.
|
||||
// nothing to generate. If line count is < 4 this sector is degenerate and should not be processed further.
|
||||
auto& entry = data[secnum].planes[plane];
|
||||
entry.vertices.Clear();
|
||||
entry.texcoords.Clear();
|
||||
|
|
|
@ -329,11 +329,6 @@ bool PickTexture(FGameTexture* tex, int paletteid, TexturePick& pick, bool wanti
|
|||
{
|
||||
if (!tex->isValid() || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return false;
|
||||
|
||||
if (tex->GetUseType() == ETextureType::FontChar && paletteid != 0)
|
||||
{
|
||||
int a = 0;
|
||||
}
|
||||
|
||||
int usepalette = 0, useremap = 0;
|
||||
if (!IsLuminosityTranslation(paletteid))
|
||||
{
|
||||
|
|
|
@ -31,68 +31,71 @@ void collectTSpritesForPortal(int x, int y, int i, int interpolation)
|
|||
int dx = mirror[j].dx;
|
||||
int dy = mirror[j].dy;
|
||||
int dz = mirror[j].dz;
|
||||
tspritetype* pTSprite = &pm_tsprite[pm_spritesortcnt++];
|
||||
*pTSprite = {};
|
||||
pTSprite->type = pSprite->type;
|
||||
pTSprite->index = pSprite->index;
|
||||
pTSprite->sectnum = nSector2;
|
||||
pTSprite->x = pSprite->x + dx;
|
||||
pTSprite->y = pSprite->y + dy;
|
||||
pTSprite->z = pSprite->z + dz;
|
||||
pTSprite->ang = pSprite->ang;
|
||||
pTSprite->picnum = pSprite->picnum;
|
||||
pTSprite->shade = pSprite->shade;
|
||||
pTSprite->pal = pSprite->pal;
|
||||
pTSprite->xrepeat = pSprite->xrepeat;
|
||||
pTSprite->yrepeat = pSprite->yrepeat;
|
||||
pTSprite->xoffset = pSprite->xoffset;
|
||||
pTSprite->yoffset = pSprite->yoffset;
|
||||
pTSprite->cstat = pSprite->cstat;
|
||||
pTSprite->statnum = kStatDecoration;
|
||||
pTSprite->owner = pSprite->index;
|
||||
pTSprite->extra = pSprite->extra;
|
||||
pTSprite->flags = pSprite->hitag | 0x200;
|
||||
pTSprite->x = dx + interpolatedvalue(pSprite->ox, pSprite->x, interpolation);
|
||||
pTSprite->y = dy + interpolatedvalue(pSprite->oy, pSprite->y, interpolation);
|
||||
pTSprite->z = dz + interpolatedvalue(pSprite->oz, pSprite->z, interpolation);
|
||||
pTSprite->ang = pSprite->interpolatedang(interpolation);
|
||||
if (pm_spritesortcnt < MAXSPRITESONSCREEN)
|
||||
{
|
||||
tspritetype* pTSprite = &pm_tsprite[pm_spritesortcnt++];
|
||||
*pTSprite = {};
|
||||
pTSprite->type = pSprite->type;
|
||||
pTSprite->index = pSprite->index;
|
||||
pTSprite->sectnum = nSector2;
|
||||
pTSprite->x = pSprite->x + dx;
|
||||
pTSprite->y = pSprite->y + dy;
|
||||
pTSprite->z = pSprite->z + dz;
|
||||
pTSprite->ang = pSprite->ang;
|
||||
pTSprite->picnum = pSprite->picnum;
|
||||
pTSprite->shade = pSprite->shade;
|
||||
pTSprite->pal = pSprite->pal;
|
||||
pTSprite->xrepeat = pSprite->xrepeat;
|
||||
pTSprite->yrepeat = pSprite->yrepeat;
|
||||
pTSprite->xoffset = pSprite->xoffset;
|
||||
pTSprite->yoffset = pSprite->yoffset;
|
||||
pTSprite->cstat = pSprite->cstat;
|
||||
pTSprite->statnum = kStatDecoration;
|
||||
pTSprite->owner = pSprite->index;
|
||||
pTSprite->extra = pSprite->extra;
|
||||
pTSprite->flags = pSprite->hitag | 0x200;
|
||||
pTSprite->x = dx + interpolatedvalue(pSprite->ox, pSprite->x, interpolation);
|
||||
pTSprite->y = dy + interpolatedvalue(pSprite->oy, pSprite->y, interpolation);
|
||||
pTSprite->z = dz + interpolatedvalue(pSprite->oz, pSprite->z, interpolation);
|
||||
pTSprite->ang = pSprite->interpolatedang(interpolation);
|
||||
|
||||
int nAnim = 0;
|
||||
switch (picanm[pTSprite->picnum].extra & 7)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
int dX = x - pTSprite->x;
|
||||
int dY = y - pTSprite->y;
|
||||
RotateVector(&dX, &dY, 128 - pTSprite->ang);
|
||||
nAnim = GetOctant(dX, dY);
|
||||
if (nAnim <= 4)
|
||||
int nAnim = 0;
|
||||
switch (picanm[pTSprite->picnum].extra & 7)
|
||||
{
|
||||
pTSprite->cstat &= ~4;
|
||||
}
|
||||
else
|
||||
case 1:
|
||||
{
|
||||
nAnim = 8 - nAnim;
|
||||
pTSprite->cstat |= 4;
|
||||
int dX = x - pTSprite->x;
|
||||
int dY = y - pTSprite->y;
|
||||
RotateVector(&dX, &dY, 128 - pTSprite->ang);
|
||||
nAnim = GetOctant(dX, dY);
|
||||
if (nAnim <= 4)
|
||||
{
|
||||
pTSprite->cstat &= ~4;
|
||||
}
|
||||
else
|
||||
{
|
||||
nAnim = 8 - nAnim;
|
||||
pTSprite->cstat |= 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
int dX = x - pTSprite->x;
|
||||
int dY = y - pTSprite->y;
|
||||
RotateVector(&dX, &dY, 128 - pTSprite->ang);
|
||||
nAnim = GetOctant(dX, dY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (nAnim > 0)
|
||||
{
|
||||
pTSprite->picnum += picanm[pTSprite->picnum].num + 1;
|
||||
nAnim--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
int dX = x - pTSprite->x;
|
||||
int dY = y - pTSprite->y;
|
||||
RotateVector(&dX, &dY, 128 - pTSprite->ang);
|
||||
nAnim = GetOctant(dX, dY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (nAnim > 0)
|
||||
{
|
||||
pTSprite->picnum += picanm[pTSprite->picnum].num + 1;
|
||||
nAnim--;
|
||||
}
|
||||
|
||||
pm_spritesortcnt++;
|
||||
pm_spritesortcnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2540,7 +2540,7 @@ void actInit(bool bSaveLoad)
|
|||
{
|
||||
if (act->s().type == kItemWeaponVoodooDoll)
|
||||
{
|
||||
act->s().type = kAmmoItemVoodooDoll;
|
||||
act->s().type = kItemAmmoVoodooDoll;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2661,7 +2661,8 @@ void actRadiusDamage(DBloodActor* source, int x, int y, int z, int nSector, int
|
|||
{
|
||||
uint8_t sectmap[(kMaxSectors + 7) >> 3];
|
||||
auto pOwner = source->GetOwner();
|
||||
GetClosestSpriteSectors(nSector, x, y, nDist, sectmap);
|
||||
const bool newSectCheckMethod = !cl_bloodvanillaexplosions && pOwner && pOwner->IsDudeActor() && !VanillaMode(); // use new sector checking logic
|
||||
GetClosestSpriteSectors(nSector, x, y, nDist, sectmap, nullptr, newSectCheckMethod);
|
||||
nDist <<= 4;
|
||||
if (flags & 2)
|
||||
{
|
||||
|
@ -3089,6 +3090,18 @@ static bool actKillDudeStage1(DBloodActor* actor, DAMAGE_TYPE damageType)
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case kDudeTinyCaleb:
|
||||
if (cl_bloodvanillaenemies || VanillaMode())
|
||||
break;
|
||||
if (damageType == kDamageBurn && pXSprite->medium == kMediumNormal)
|
||||
{
|
||||
pSprite->type = kDudeBurningTinyCaleb;
|
||||
aiNewState(actor, &tinycalebBurnGoto);
|
||||
actHealDude(actor, dudeInfo[39].startHealth, dudeInfo[39].startHealth);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -3923,7 +3936,7 @@ static void actImpactMissile(DBloodActor* missileActor, int hitCode)
|
|||
actBurnSprite(missileActor->GetOwner(), actorHit, 360);
|
||||
|
||||
// by NoOne: make Life Leech heal user, just like it was in 1.0x versions
|
||||
if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus() && pDudeInfo != nullptr)
|
||||
if (gGameOptions.weaponsV10x && !VanillaMode() && pDudeInfo != nullptr)
|
||||
{
|
||||
if (missileOwner->IsDudeActor() && missileOwner->hasX() && missileOwner->x().health != 0)
|
||||
actHealDude(missileOwner, nDamage >> 2, getDudeInfo(missileOwner->s().type)->startHealth);
|
||||
|
@ -3999,7 +4012,7 @@ static void actImpactMissile(DBloodActor* missileActor, int hitCode)
|
|||
break;
|
||||
|
||||
case kMissileFireball:
|
||||
case kMissileFireballNapam:
|
||||
case kMissileFireballNapalm:
|
||||
if (hitCode == 3 && pSpriteHit && (pThingInfo || pDudeInfo))
|
||||
{
|
||||
if (pThingInfo && pSpriteHit->type == kThingTNTBarrel && actorHit->x().burnTime == 0)
|
||||
|
@ -4029,7 +4042,7 @@ static void actImpactMissile(DBloodActor* missileActor, int hitCode)
|
|||
actRadiusDamage(missileOwner, pMissile->x, pMissile->y, pMissile->z, pMissile->sectnum, 16, 20, 10, kDamageBullet, 6, 480);
|
||||
|
||||
// by NoOne: allow additional bullet damage for Flare Gun
|
||||
if (gGameOptions.weaponsV10x && !VanillaMode() && !DemoRecordStatus())
|
||||
if (gGameOptions.weaponsV10x && !VanillaMode())
|
||||
{
|
||||
int nDamage = (20 + Random(10)) << 4;
|
||||
actDamageSprite(missileOwner, actorHit, kDamageBullet, nDamage);
|
||||
|
@ -4560,7 +4573,7 @@ static void ProcessTouchObjects(DBloodActor* actor)
|
|||
}
|
||||
}
|
||||
|
||||
if (actor2->hasX())
|
||||
if (actor2 && actor2->hasX())
|
||||
{
|
||||
XSPRITE* pXHSprite = &actor2->x();
|
||||
if (pXHSprite->Touch && !pXHSprite->isTriggered && (!pXHSprite->DudeLockout || actor->IsPlayerActor()))
|
||||
|
@ -4633,11 +4646,15 @@ int MoveThing(spritetype *pSprite)
|
|||
assert(nSector >= 0 && nSector < kMaxSectors);
|
||||
int top, bottom;
|
||||
GetSpriteExtents(pSprite, &top, &bottom);
|
||||
const int bakCompat = enginecompatibility_mode;
|
||||
if (xvel[nSprite] || yvel[nSprite])
|
||||
{
|
||||
short bakCstat = pSprite->cstat;
|
||||
pSprite->cstat &= ~257;
|
||||
if ((pSprite->owner >= 0) && !cl_bloodvanillaexplosions && !VanillaMode())
|
||||
enginecompatibility_mode = ENGINECOMPATIBILITY_NONE; // improved clipmove accuracy
|
||||
v8 = gSpriteHit[nXSprite].hit = ClipMove((int*)&pSprite->x, (int*)&pSprite->y, (int*)&pSprite->z, &nSector, xvel[nSprite]>>12, yvel[nSprite]>>12, pSprite->clipdist<<2, (pSprite->z-top)/4, (bottom-pSprite->z)/4, CLIPMASK0);
|
||||
enginecompatibility_mode = bakCompat; // restore
|
||||
pSprite->cstat = bakCstat;
|
||||
assert(nSector >= 0);
|
||||
if (pSprite->sectnum != nSector)
|
||||
|
@ -4817,6 +4834,8 @@ void MoveDude(spritetype *pSprite)
|
|||
int tz = (pSprite->z-top)/4;
|
||||
int wd = pSprite->clipdist<<2;
|
||||
int nSector = pSprite->sectnum;
|
||||
int nAiStateType = (pXSprite->aiState) ? pXSprite->aiState->stateType : -1;
|
||||
|
||||
assert(nSector >= 0 && nSector < kMaxSectors);
|
||||
if (xvel[nSprite] || yvel[nSprite])
|
||||
{
|
||||
|
@ -4997,8 +5016,12 @@ void MoveDude(spritetype *pSprite)
|
|||
}
|
||||
if (pPlayer && zvel[nSprite] > 0x155555 && !pPlayer->fallScream && pXSprite->height > 0)
|
||||
{
|
||||
pPlayer->fallScream = 1;
|
||||
sfxPlay3DSound(pSprite, 719, 0, 0);
|
||||
const bool playerAlive = (pXSprite->health > 0) || VanillaMode(); // only trigger falling scream if player is alive or vanilla mode
|
||||
if (playerAlive)
|
||||
{
|
||||
pPlayer->fallScream = 1;
|
||||
sfxPlay3DSound(pSprite, 719, 0, 0);
|
||||
}
|
||||
}
|
||||
vec3_t const oldpos = pSprite->pos;
|
||||
int nLink = CheckLink(pSprite);
|
||||
|
@ -5028,6 +5051,7 @@ void MoveDude(spritetype *pSprite)
|
|||
}
|
||||
sfxPlay3DSound(pSprite, 721, -1, 0);
|
||||
} else {
|
||||
|
||||
switch (pSprite->type) {
|
||||
case kDudeCultistTommy:
|
||||
case kDudeCultistShotgun:
|
||||
|
@ -5041,6 +5065,11 @@ void MoveDude(spritetype *pSprite)
|
|||
actKillDude(pSprite->index, pSprite, kDamageFall, 1000<<4);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
if (IsDudeSprite(pSprite) && pXSprite->health > 0 && aiInPatrolState(nAiStateType))
|
||||
aiPatrolState(pSprite, kAiStatePatrolMoveL); // continue patrol when going from water
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case kMarkerUpWater:
|
||||
|
@ -5058,10 +5087,12 @@ void MoveDude(spritetype *pSprite)
|
|||
{
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
// look for palette in data2 of marker. If value <= 0, use default ones.
|
||||
pPlayer->nWaterPal = 0;
|
||||
int nXUpper = sprite[gUpperLink[nSector]].extra;
|
||||
if (nXUpper >= 0)
|
||||
pPlayer->nWaterPal = xsprite[nXUpper].data2;
|
||||
if (gModernMap) {
|
||||
pPlayer->nWaterPal = 0;
|
||||
int nXUpper = sprite[gUpperLink[nSector]].extra;
|
||||
if (nXUpper >= 0)
|
||||
pPlayer->nWaterPal = xsprite[nXUpper].data2;
|
||||
}
|
||||
#endif
|
||||
|
||||
pPlayer->posture = 1;
|
||||
|
@ -5072,6 +5103,7 @@ void MoveDude(spritetype *pSprite)
|
|||
}
|
||||
else
|
||||
{
|
||||
|
||||
switch (pSprite->type) {
|
||||
case kDudeCultistTommy:
|
||||
case kDudeCultistShotgun:
|
||||
|
@ -5082,22 +5114,17 @@ void MoveDude(spritetype *pSprite)
|
|||
break;
|
||||
case kDudeBurningCultist:
|
||||
{
|
||||
const bool fixRandomCultist = !cl_bloodvanillaenemies && (pSprite->inittype >= kDudeBase) && (pSprite->inittype < kDudeMax) && !VanillaMode(); // fix burning cultists randomly switching types underwater
|
||||
if (Chance(chance))
|
||||
{
|
||||
pSprite->type = kDudeCultistTommy;
|
||||
pXSprite->burnTime = 0;
|
||||
evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
|
||||
sfxPlay3DSound(pSprite, 720, -1, 0);
|
||||
aiNewState(&bloodActors[pXSprite->reference], &cultistSwimGoto);
|
||||
}
|
||||
else
|
||||
{
|
||||
pSprite->type = kDudeCultistShotgun;
|
||||
pXSprite->burnTime = 0;
|
||||
evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
|
||||
sfxPlay3DSound(pSprite, 720, -1, 0);
|
||||
aiNewState(&bloodActors[pXSprite->reference], &cultistSwimGoto);
|
||||
}
|
||||
if (fixRandomCultist) // fix burning cultists randomly switching types underwater
|
||||
pSprite->type = pSprite->inittype; // restore back to spawned cultist type
|
||||
pXSprite->burnTime = 0;
|
||||
evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
|
||||
sfxPlay3DSound(pSprite, 720, -1, 0);
|
||||
aiNewState(&bloodActors[pXSprite->reference], &cultistSwimGoto);
|
||||
break;
|
||||
}
|
||||
case kDudeZombieAxeNormal:
|
||||
|
@ -5130,14 +5157,26 @@ void MoveDude(spritetype *pSprite)
|
|||
case kDudeBurningInnocent:
|
||||
actKillDude(pSprite->index, pSprite, kDamageFall, 1000 << 4);
|
||||
break;
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
case kDudeModernCustom:
|
||||
evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
|
||||
if (!canSwim(pSprite)) actKillDude(pSprite->index, pSprite, kDamageFall, 1000 << 4);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
if (gModernMap) {
|
||||
|
||||
if (pSprite->type == kDudeModernCustom) {
|
||||
|
||||
evPost(nSprite, 3, 0, kCallbackEnemeyBubble);
|
||||
if (!canSwim(pSprite))
|
||||
actKillDude(pSprite->index, pSprite, kDamageFall, 1000 << 4);
|
||||
|
||||
}
|
||||
|
||||
// continue patrol when fall into water
|
||||
if (IsDudeSprite(pSprite) && pXSprite->health > 0 && aiInPatrolState(nAiStateType))
|
||||
aiPatrolState(pSprite, kAiStatePatrolMoveW);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -5207,7 +5246,7 @@ void MoveDude(spritetype *pSprite)
|
|||
case kDudeBat:
|
||||
case kDudeRat:
|
||||
case kDudeBurningInnocent:
|
||||
actKillDude(pSprite->index, pSprite, DAMAGE_TYPE_0, 1000<<4);
|
||||
actKillDude(pSprite->index, pSprite, kDamageFall, 1000<<4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -5392,6 +5431,8 @@ int MoveMissile(spritetype *pSprite)
|
|||
int top, bottom;
|
||||
GetSpriteExtents(pSprite, &top, &bottom);
|
||||
int i = 1;
|
||||
const int bakCompat = enginecompatibility_mode;
|
||||
const bool isFlameSprite = (pSprite->type == kMissileFlameSpray || pSprite->type == kMissileFlameHound); // do not use accurate clipmove for flame based sprites (changes damage too much)
|
||||
while (1)
|
||||
{
|
||||
int x = pSprite->x;
|
||||
|
@ -5399,7 +5440,10 @@ int MoveMissile(spritetype *pSprite)
|
|||
int z = pSprite->z;
|
||||
int nSector2 = pSprite->sectnum;
|
||||
clipmoveboxtracenum = 1;
|
||||
if ((pSprite->owner >= 0) && !isFlameSprite && !cl_bloodvanillaexplosions && !VanillaMode())
|
||||
enginecompatibility_mode = ENGINECOMPATIBILITY_NONE; // improved clipmove accuracy
|
||||
int vdx = ClipMove(&x, &y, &z, &nSector2, vx, vy, pSprite->clipdist<<2, (z-top)/4, (bottom-z)/4, CLIPMASK0);
|
||||
enginecompatibility_mode = bakCompat; // restore
|
||||
clipmoveboxtracenum = 3;
|
||||
short nSector = nSector2;
|
||||
if (nSector2 < 0)
|
||||
|
@ -5512,7 +5556,7 @@ void actExplodeSprite(spritetype *pSprite)
|
|||
|
||||
switch (pSprite->type)
|
||||
{
|
||||
case kMissileFireballNapam:
|
||||
case kMissileFireballNapalm:
|
||||
nType = kExplosionNapalm;
|
||||
seqSpawn(4, 3, nXSprite, -1);
|
||||
if (Chance(0x8000))
|
||||
|
@ -5939,7 +5983,7 @@ void actProcessSprites(void)
|
|||
it.Reset(kStatExplosion);
|
||||
while ((nSprite = it.NextIndex()) >= 0)
|
||||
{
|
||||
uint8_t v24c[(kMaxSectors+7)>>3];
|
||||
uint8_t sectmap[(kMaxSectors+7)>>3];
|
||||
spritetype *pSprite = &sprite[nSprite];
|
||||
|
||||
if (pSprite->flags & 32)
|
||||
|
@ -5964,9 +6008,13 @@ void actProcessSprites(void)
|
|||
if (gModernMap && pXSprite->data4 > 0)
|
||||
radius = pXSprite->data4;
|
||||
#endif
|
||||
|
||||
|
||||
// GetClosestSpriteSectors() has issues checking some sectors due to optimizations
|
||||
// the new flag newSectCheckMethod for GetClosestSpriteSectors() does rectify these issues, but this may cause unintended side effects for level scripted explosions
|
||||
// so only allow this new checking method for dude spawned explosions
|
||||
short gAffectedXWalls[kMaxXWalls];
|
||||
GetClosestSpriteSectors(nSector, x, y, radius, v24c, gAffectedXWalls);
|
||||
const bool newSectCheckMethod = !cl_bloodvanillaexplosions && pOwner && pOwner->IsDudeActor() && !VanillaMode(); // use new sector checking logic
|
||||
GetClosestSpriteSectors(nSector, x, y, radius, sectmap, gAffectedXWalls, newSectCheckMethod);
|
||||
|
||||
for (int i = 0; i < kMaxXWalls; i++)
|
||||
{
|
||||
|
@ -5986,7 +6034,7 @@ void actProcessSprites(void)
|
|||
|
||||
if (pDude->flags & 32)
|
||||
continue;
|
||||
if (TestBitString(v24c, pDude->sectnum))
|
||||
if (TestBitString(sectmap, pDude->sectnum))
|
||||
{
|
||||
if (pXSprite->data1 && CheckProximity(pDude, x, y, z, nSector, radius))
|
||||
{
|
||||
|
@ -6017,7 +6065,7 @@ void actProcessSprites(void)
|
|||
|
||||
if (pThing->flags & 32)
|
||||
continue;
|
||||
if (TestBitString(v24c, pThing->sectnum))
|
||||
if (TestBitString(sectmap, pThing->sectnum))
|
||||
{
|
||||
if (pXSprite->data1 && CheckProximity(pThing, x, y, z, nSector, radius))
|
||||
{
|
||||
|
@ -6061,7 +6109,7 @@ void actProcessSprites(void)
|
|||
continue;
|
||||
|
||||
spritetype* pDebris = &sprite[gPhysSpritesList[i]];
|
||||
if (!TestBitString(v24c, pDebris->sectnum) || !CheckProximity(pDebris, x, y, z, nSector, radius)) continue;
|
||||
if (!TestBitString(sectmap, pDebris->sectnum) || !CheckProximity(pDebris, x, y, z, nSector, radius)) continue;
|
||||
else debrisConcuss(nOwner, i, x, y, z, pExplodeInfo->dmgType);
|
||||
}
|
||||
}
|
||||
|
@ -6073,8 +6121,11 @@ void actProcessSprites(void)
|
|||
else if (sprite[gImpactSpritesList[i]].sectnum < 0 || (sprite[gImpactSpritesList[i]].flags & kHitagFree) != 0)
|
||||
continue;
|
||||
|
||||
spritetype* pImpact = &sprite[gImpactSpritesList[i]]; XSPRITE* pXImpact = &xsprite[pImpact->extra];
|
||||
if (/*pXImpact->state == pXImpact->restState ||*/ !TestBitString(v24c, pImpact->sectnum) || !CheckProximity(pImpact, x, y, z, nSector, radius))
|
||||
spritetype* pImpact = &sprite[gImpactSpritesList[i]];
|
||||
if (pImpact->extra <= 0)
|
||||
continue;
|
||||
XSPRITE* pXImpact = &xsprite[pImpact->extra];
|
||||
if (/*pXImpact->state == pXImpact->restState ||*/ !TestBitString(sectmap, pImpact->sectnum) || !CheckProximity(pImpact, x, y, z, nSector, radius))
|
||||
continue;
|
||||
|
||||
trTriggerSprite(pImpact->index, pXImpact, kCmdSpriteImpact);
|
||||
|
@ -6155,7 +6206,8 @@ void actProcessSprites(void)
|
|||
if (nXSprite > 0)
|
||||
{
|
||||
XSPRITE *pXSprite = &xsprite[nXSprite];
|
||||
if (pXSprite->burnTime > 0)
|
||||
const bool fixBurnGlitch = !cl_bloodvanillaenemies && IsBurningDude(pSprite) && !VanillaMode(); // if enemies are burning, always apply burning damage per tick
|
||||
if ((pXSprite->burnTime > 0) || fixBurnGlitch)
|
||||
{
|
||||
switch (pSprite->type)
|
||||
{
|
||||
|
@ -6667,7 +6719,7 @@ void actBuildMissile(spritetype* pMissile, int nXSprite, int nSprite) {
|
|||
seqSpawn(2, 3, nXSprite, -1);
|
||||
sfxPlay3DSound(pMissile, 493, 0, 0);
|
||||
break;
|
||||
case kMissileFireballNapam:
|
||||
case kMissileFireballNapalm:
|
||||
seqSpawn(61, 3, nXSprite, nNapalmClient);
|
||||
sfxPlay3DSound(pMissile, 441, 0, 0);
|
||||
break;
|
||||
|
@ -7016,22 +7068,34 @@ void actFireVector(spritetype *pShooter, int a2, int a3, int a4, int a5, int a6,
|
|||
#ifdef NOONE_EXTENSIONS
|
||||
// add impulse for sprites from physics list
|
||||
if (gPhysSpritesCount > 0 && pVectorData->impulse) {
|
||||
int nIndex = debrisGetIndex(pSprite->index);
|
||||
if (nIndex != -1 && (xsprite[pSprite->extra].physAttr & kPhysDebrisVector)) {
|
||||
int impulse = DivScale(pVectorData->impulse, ClipLow(gSpriteMass[pSprite->extra].mass, 10), 6);
|
||||
xvel[nSprite] += MulScale(a4, impulse, 16);
|
||||
yvel[nSprite] += MulScale(a5, impulse, 16);
|
||||
zvel[nSprite] += MulScale(a6, impulse, 16);
|
||||
|
||||
if (xspriRangeIsFine(pSprite->extra)) {
|
||||
|
||||
XSPRITE* pXSprite = &xsprite[pSprite->extra];
|
||||
if (pXSprite->physAttr & kPhysDebrisVector) {
|
||||
|
||||
int impulse = DivScale(pVectorData->impulse, ClipLow(gSpriteMass[pSprite->extra].mass, 10), 6);
|
||||
xvel[nSprite] += MulScale(a4, impulse, 16);
|
||||
yvel[nSprite] += MulScale(a5, impulse, 16);
|
||||
zvel[nSprite] += MulScale(a6, impulse, 16);
|
||||
|
||||
if (pVectorData->burnTime != 0) {
|
||||
if (!xsprite[nXSprite].burnTime) evPost(nSprite, 3, 0, kCallbackFXFlameLick);
|
||||
actBurnSprite(sprite[nShooter].owner, &xsprite[nXSprite], pVectorData->burnTime);
|
||||
}
|
||||
|
||||
if (pSprite->type >= kThingBase && pSprite->type < kThingMax) {
|
||||
pSprite->statnum = kStatThing; // temporary change statnum property
|
||||
actDamageSprite(nShooter, pSprite, pVectorData->dmgType, pVectorData->dmg << 4);
|
||||
pSprite->statnum = kStatDecoration; // return statnum property back
|
||||
}
|
||||
|
||||
if (pVectorData->burnTime != 0) {
|
||||
if (!xsprite[nXSprite].burnTime) evPost(nSprite, 3, 0, kCallbackFXFlameLick);
|
||||
actBurnSprite(sprite[nShooter].owner, &xsprite[nXSprite], pVectorData->burnTime);
|
||||
}
|
||||
|
||||
//if (pSprite->type >= kThingBase && pSprite->type < kThingMax)
|
||||
//changespritestat(pSprite->index, kStatThing);
|
||||
//actPostSprite(pSprite->index, kStatThing); // if it was a thing, return it's statnum back
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
@ -7039,10 +7103,32 @@ void actFireVector(spritetype *pShooter, int a2, int a3, int a4, int a5, int a6,
|
|||
}
|
||||
}
|
||||
assert(nSurf < kSurfMax);
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
|
||||
// let the patrol enemies hear surface hit sounds!
|
||||
|
||||
if (pVectorData->surfHit[nSurf].fx2 >= 0) {
|
||||
|
||||
spritetype* pFX2 = gFX.fxSpawn(pVectorData->surfHit[nSurf].fx2, nSector, x, y, z, 0);
|
||||
if (pFX2 && gModernMap)
|
||||
pFX2->owner = pShooter->index;
|
||||
}
|
||||
|
||||
if (pVectorData->surfHit[nSurf].fx3 >= 0) {
|
||||
|
||||
spritetype* pFX3 = gFX.fxSpawn(pVectorData->surfHit[nSurf].fx3, nSector, x, y, z, 0);
|
||||
if (pFX3 && gModernMap)
|
||||
pFX3->owner = pShooter->index;
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
if (pVectorData->surfHit[nSurf].fx2 >= 0)
|
||||
gFX.fxSpawn(pVectorData->surfHit[nSurf].fx2, nSector, x, y, z, 0);
|
||||
if (pVectorData->surfHit[nSurf].fx3 >= 0)
|
||||
gFX.fxSpawn(pVectorData->surfHit[nSurf].fx3, nSector, x, y, z, 0);
|
||||
#endif
|
||||
|
||||
if (pVectorData->surfHit[nSurf].fxSnd >= 0)
|
||||
sfxPlay3DSound(x, y, z, pVectorData->surfHit[nSurf].fxSnd, nSector);
|
||||
}
|
||||
|
|
|
@ -209,6 +209,12 @@ void actAddGameLight(int lightRadius, int spriteNum, int zOffset, int lightRange
|
|||
void actDoLight(int spriteNum);
|
||||
#endif
|
||||
|
||||
void FireballSeqCallback(int, int);
|
||||
void sub_38938(int, int);
|
||||
void NapalmSeqCallback(int, int);
|
||||
void sub_3888C(int, int);
|
||||
void TreeToGibCallback(int, int);
|
||||
|
||||
bool IsUnderwaterSector(int nSector);
|
||||
void actInit(bool bSaveLoad);
|
||||
int actWallBounceVector(int *x, int *y, int nWall, int a4);
|
||||
|
|
|
@ -177,7 +177,7 @@ bool CanMove(spritetype *pSprite, int a2, int nAngle, int nRange)
|
|||
// It makes ignore danger if enemy immune to N damageType. As result Cerberus start acting like
|
||||
// in Blood 1.0 so it can move normally to player. It's up to you for adding rest of enemies here as
|
||||
// i don't think it will broke something in game.
|
||||
if (!VanillaMode() && Crusher && isImmune(pSprite, pXSector->damageType, 16)) return true;
|
||||
if (!cl_bloodvanillaenemies && !VanillaMode() && Crusher && isImmune(pSprite, pXSector->damageType, 16)) return true;
|
||||
fallthrough__;
|
||||
case kDudeZombieButcher:
|
||||
case kDudeSpiderBrown:
|
||||
|
@ -896,11 +896,24 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
|
|||
spritetype *pSource = &source->s();
|
||||
int nSource = pSource->index;
|
||||
if (pSprite == pSource) return 0;
|
||||
else if (pXSprite->target == -1 || (nSource != pXSprite->target && Chance(pSprite->type == pSource->type ? nDamage*pDudeInfo->changeTargetKin : nDamage*pDudeInfo->changeTarget)))
|
||||
else if (pXSprite->target == -1) // if no target, give the dude a target
|
||||
{
|
||||
aiSetTarget(pXSprite, nSource);
|
||||
aiActivateDude(&bloodActors[pXSprite->reference]);
|
||||
}
|
||||
else if (nSource != pXSprite->target) // if found a new target, retarget
|
||||
{
|
||||
int nThresh = nDamage;
|
||||
if (pSprite->type == pSource->type)
|
||||
nThresh *= pDudeInfo->changeTargetKin;
|
||||
else
|
||||
nThresh *= pDudeInfo->changeTarget;
|
||||
if (Chance(nThresh))
|
||||
{
|
||||
aiSetTarget(pXSprite, nSource);
|
||||
aiActivateDude(&bloodActors[pXSprite->reference]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NOONE_EXTENSIONS
|
||||
if (gModernMap) {
|
||||
|
@ -1020,6 +1033,7 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
|
|||
DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra];
|
||||
pDudeExtra->recoil = 1;
|
||||
}
|
||||
const bool fixRandomCultist = !cl_bloodvanillaenemies && (pSprite->inittype >= kDudeBase) && (pSprite->inittype < kDudeMax) && !VanillaMode(); // fix burning cultists randomly switching types underwater
|
||||
switch (pSprite->type)
|
||||
{
|
||||
case kDudeCultistTommy:
|
||||
|
@ -1066,12 +1080,16 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
|
|||
if (Chance(0x600) && (pXSprite->medium == kMediumWater || pXSprite->medium == kMediumGoo))
|
||||
{
|
||||
pSprite->type = kDudeCultistTommy;
|
||||
if (fixRandomCultist) // fix burning cultists randomly switching types underwater
|
||||
pSprite->type = pSprite->inittype; // restore back to spawned cultist type
|
||||
pXSprite->burnTime = 0;
|
||||
aiNewState(actor, &cultistSwimGoto);
|
||||
}
|
||||
else if (pXSprite->medium == kMediumWater || pXSprite->medium == kMediumGoo)
|
||||
{
|
||||
pSprite->type = kDudeCultistShotgun;
|
||||
if (fixRandomCultist) // fix burning cultists randomly switching types underwater
|
||||
pSprite->type = pSprite->inittype; // restore back to spawned cultist type
|
||||
pXSprite->burnTime = 0;
|
||||
aiNewState(actor, &cultistSwimGoto);
|
||||
}
|
||||
|
@ -1092,8 +1110,16 @@ int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType
|
|||
case kDudeTinyCaleb:
|
||||
if (nDmgType == kDamageBurn && pXSprite->health <= (unsigned int)pDudeInfo->fleeHealth/* && (pXSprite->at17_6 != 1 || pXSprite->at17_6 != 2)*/)
|
||||
{
|
||||
pSprite->type = kDudeBurningInnocent;
|
||||
aiNewState(actor, &cultistBurnGoto);
|
||||
if (!cl_bloodvanillaenemies && !VanillaMode()) // fix burning sprite for tiny caleb
|
||||
{
|
||||
pSprite->type = kDudeBurningTinyCaleb;
|
||||
aiNewState(actor, &tinycalebBurnGoto);
|
||||
}
|
||||
else
|
||||
{
|
||||
pSprite->type = kDudeBurningInnocent;
|
||||
aiNewState(actor, &cultistBurnGoto);
|
||||
}
|
||||
aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1);
|
||||
gDudeExtra[pSprite->extra].time = PlayClock+360;
|
||||
actHealDude(pXSprite, dudeInfo[39].startHealth, dudeInfo[39].startHealth);
|
||||
|
@ -1415,7 +1441,7 @@ void aiThinkTarget(DBloodActor* actor)
|
|||
}
|
||||
}
|
||||
|
||||
void sub_5F15C(spritetype *pSprite, XSPRITE *pXSprite)
|
||||
void aiLookForTarget(spritetype *pSprite, XSPRITE *pXSprite)
|
||||
{
|
||||
assert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
|
||||
DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
|
||||
|
@ -1453,8 +1479,9 @@ void sub_5F15C(spritetype *pSprite, XSPRITE *pXSprite)
|
|||
}
|
||||
if (pXSprite->state)
|
||||
{
|
||||
uint8_t va4[(kMaxSectors+7)>>3];
|
||||
GetClosestSpriteSectors(pSprite->sectnum, pSprite->x, pSprite->y, 400, va4);
|
||||
uint8_t sectmap[(kMaxSectors+7)>>3];
|
||||
const bool newSectCheckMethod = !cl_bloodvanillaenemies && !VanillaMode(); // use new sector checking logic
|
||||
GetClosestSpriteSectors(pSprite->sectnum, pSprite->x, pSprite->y, 400, sectmap, nullptr, newSectCheckMethod);
|
||||
|
||||
int nSprite2;
|
||||
StatIterator it(kStatDude);
|
||||
|
@ -1492,10 +1519,10 @@ void aiProcessDudes(void) {
|
|||
if (IsPlayerSprite(pSprite) || pXSprite->health == 0) continue;
|
||||
pXSprite->stateTimer = ClipLow(pXSprite->stateTimer-4, 0);
|
||||
|
||||
if (pXSprite->aiState->moveFunc)
|
||||
if (pXSprite->aiState && pXSprite->aiState->moveFunc)
|
||||
pXSprite->aiState->moveFunc(&bloodActors[pXSprite->reference]);
|
||||
|
||||
if (pXSprite->aiState->thinkFunc && (gFrameCount & 3) == (nSprite & 3))
|
||||
if (pXSprite->aiState && pXSprite->aiState->thinkFunc && (gFrameCount & 3) == (nSprite & 3))
|
||||
pXSprite->aiState->thinkFunc(&bloodActors[pXSprite->reference]);
|
||||
|
||||
switch (pSprite->type) {
|
||||
|
@ -1505,7 +1532,7 @@ void aiProcessDudes(void) {
|
|||
GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index];
|
||||
if (pExtra->slaveCount > 0) updateTargetOfSlaves(pSprite);
|
||||
if (pExtra->nLifeLeech >= 0) updateTargetOfLeech(pSprite);
|
||||
if (pXSprite->stateTimer == 0 && pXSprite->aiState->nextState
|
||||
if (pXSprite->stateTimer == 0 && pXSprite->aiState && pXSprite->aiState->nextState
|
||||
&& (pXSprite->aiState->stateTicks > 0 || seqGetStatus(3, pSprite->extra) < 0)) {
|
||||
aiGenDudeNewState(pSprite, pXSprite->aiState->nextState);
|
||||
}
|
||||
|
@ -1517,7 +1544,7 @@ void aiProcessDudes(void) {
|
|||
}
|
||||
#endif
|
||||
default:
|
||||
if (pXSprite->stateTimer == 0 && pXSprite->aiState->nextState) {
|
||||
if (pXSprite->stateTimer == 0 && pXSprite->aiState && pXSprite->aiState->nextState) {
|
||||
if (pXSprite->aiState->stateTicks > 0)
|
||||
aiNewState(actor, pXSprite->aiState->nextState);
|
||||
else if (seqGetStatus(3, nXSprite) < 0)
|
||||
|
@ -1813,6 +1840,10 @@ void aiInitSprite(spritetype *pSprite)
|
|||
|
||||
// make dude follow the markers
|
||||
bool uwater = spriteIsUnderwater(pSprite);
|
||||
if (pXSprite->target <= 0 || sprite[pXSprite->target].type != kMarkerPath) {
|
||||
pXSprite->target = -1; aiPatrolSetMarker(pSprite, pXSprite);
|
||||
}
|
||||
|
||||
if (stateTimer > 0) {
|
||||
if (uwater) aiPatrolState(pSprite, kAiStatePatrolWaitW);
|
||||
else if (pXSprite->unused1 & kDudeFlagCrouch) aiPatrolState(pSprite, kAiStatePatrolWaitC);
|
||||
|
|
|
@ -101,7 +101,7 @@ void aiSetTarget(XSPRITE *pXSprite, int x, int y, int z);
|
|||
void aiSetTarget(XSPRITE *pXSprite, int nTarget);
|
||||
int aiDamageSprite(DBloodActor* source, DBloodActor* actor, DAMAGE_TYPE nDmgType, int nDamage);
|
||||
void aiThinkTarget(DBloodActor* actor);
|
||||
void sub_5F15C(spritetype *pSprite, XSPRITE *pXSprite);
|
||||
void aiLookForTarget(spritetype *pSprite, XSPRITE *pXSprite);
|
||||
void aiProcessDudes(void);
|
||||
void aiInit(void);
|
||||
void aiInitSprite(spritetype *pSprite);
|
||||
|
|
|
@ -82,7 +82,7 @@ void SlashSeqCallback(int, DBloodActor* actor)
|
|||
|
||||
void StompSeqCallback(int, DBloodActor* actor1)
|
||||
{
|
||||
uint8_t vb8[(kMaxSectors+7)>>3];
|
||||
uint8_t sectmap[(kMaxSectors+7)>>3];
|
||||
XSPRITE* pXSprite = &actor1->x();
|
||||
int nSprite = pXSprite->reference;
|
||||
spritetype *pSprite = &actor1->s();
|
||||
|
@ -95,7 +95,8 @@ void StompSeqCallback(int, DBloodActor* actor1)
|
|||
int nSector = pSprite->sectnum;
|
||||
int v1c = 5+2*gGameOptions.nDifficulty;
|
||||
int v10 = 25+30*gGameOptions.nDifficulty;
|
||||
GetClosestSpriteSectors(nSector, x, y, vc, vb8);
|
||||
const bool newSectCheckMethod = !cl_bloodvanillaenemies && !VanillaMode(); // use new sector checking logic
|
||||
GetClosestSpriteSectors(nSector, x, y, vc, sectmap, nullptr, newSectCheckMethod);
|
||||
char v4 = 0;
|
||||
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
|
||||
DBloodActor* actor2 = nullptr;
|
||||
|
@ -119,7 +120,7 @@ void StompSeqCallback(int, DBloodActor* actor1)
|
|||
continue;
|
||||
if (pSprite2->flags&32)
|
||||
continue;
|
||||
if (TestBitString(vb8, pSprite2->sectnum) && CheckProximity(pSprite2, x, y, z, nSector, vc))
|
||||
if (TestBitString(sectmap, pSprite2->sectnum) && CheckProximity(pSprite2, x, y, z, nSector, vc))
|
||||
{
|
||||
int top, bottom;
|
||||
GetSpriteExtents(pSprite, &top, &bottom);
|
||||
|
@ -150,7 +151,7 @@ void StompSeqCallback(int, DBloodActor* actor1)
|
|||
spritetype *pSprite2 = &sprite[nSprite2];
|
||||
if (pSprite2->flags&32)
|
||||
continue;
|
||||
if (TestBitString(vb8, pSprite2->sectnum) && CheckProximity(pSprite2, x, y, z, nSector, vc))
|
||||
if (TestBitString(sectmap, pSprite2->sectnum) && CheckProximity(pSprite2, x, y, z, nSector, vc))
|
||||
{
|
||||
XSPRITE *pXSprite = &xsprite[pSprite2->extra];
|
||||
if (pXSprite->locked)
|
||||
|
|
|
@ -202,7 +202,7 @@ static void cultThinkSearch(DBloodActor* actor)
|
|||
auto pXSprite = &actor->x();
|
||||
auto pSprite = &actor->s();
|
||||
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
|
||||
sub_5F15C(pSprite, pXSprite);
|
||||
aiLookForTarget(pSprite, pXSprite);
|
||||
}
|
||||
|
||||
static void cultThinkGoto(DBloodActor* actor)
|
||||
|
@ -303,7 +303,6 @@ static void cultThinkChase(DBloodActor* actor)
|
|||
actor->dudeSlope = DivScale(pTarget->z-pSprite->z, nDist, 10);
|
||||
switch (pSprite->type) {
|
||||
case kDudeCultistTommy:
|
||||
#if 0 // apparently this can never be entered.
|
||||
if (nDist < 0x1e00 && nDist > 0xe00 && abs(nDeltaAngle) < 85 && !TargetNearExplosion(pTarget)
|
||||
&& (pTarget->flags&2) && gGameOptions.nDifficulty > 2 && IsPlayerSprite(pTarget) && gPlayer[pTarget->type-kDudePlayer1].isRunning
|
||||
&& Chance(0x8000))
|
||||
|
@ -327,9 +326,7 @@ static void cultThinkChase(DBloodActor* actor)
|
|||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (nDist < 0x4600 && abs(nDeltaAngle) < 28)
|
||||
else if (nDist < 0x4600 && abs(nDeltaAngle) < 28)
|
||||
{
|
||||
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
|
||||
switch (hit)
|
||||
|
@ -375,7 +372,7 @@ static void cultThinkChase(DBloodActor* actor)
|
|||
break;
|
||||
case kDudeCultistShotgun:
|
||||
if (nDist < 0x2c00 && nDist > 0x1400 && !TargetNearExplosion(pTarget)
|
||||
&& (pTarget->flags&2) && gGameOptions.nDifficulty >= 2 && IsPlayerSprite(pTarget) /*&& !gPlayer[pTarget->type-kDudePlayer1].isRunning*/
|
||||
&& (pTarget->flags&2) && gGameOptions.nDifficulty >= 2 && IsPlayerSprite(pTarget) && !gPlayer[pTarget->type-kDudePlayer1].isRunning
|
||||
&& Chance(0x8000))
|
||||
{
|
||||
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
|
||||
|
@ -442,7 +439,6 @@ static void cultThinkChase(DBloodActor* actor)
|
|||
}
|
||||
break;
|
||||
case kDudeCultistTesla:
|
||||
#if 0
|
||||
if (nDist < 0x1e00 && nDist > 0xe00 && !TargetNearExplosion(pTarget)
|
||||
&& (pTarget->flags&2) && gGameOptions.nDifficulty > 2 && IsPlayerSprite(pTarget) && gPlayer[pTarget->type-kDudePlayer1].isRunning
|
||||
&& Chance(0x8000))
|
||||
|
@ -466,9 +462,7 @@ static void cultThinkChase(DBloodActor* actor)
|
|||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (nDist < 0x3200 && abs(nDeltaAngle) < 28)
|
||||
else if (nDist < 0x3200 && abs(nDeltaAngle) < 28)
|
||||
{
|
||||
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
|
||||
switch (hit)
|
||||
|
@ -557,7 +551,6 @@ static void cultThinkChase(DBloodActor* actor)
|
|||
}
|
||||
break;
|
||||
case kDudeCultistBeast:
|
||||
#if 0
|
||||
if (nDist < 0x1e00 && nDist > 0xe00 && !TargetNearExplosion(pTarget)
|
||||
&& (pTarget->flags&2) && gGameOptions.nDifficulty > 2 && IsPlayerSprite(pTarget) && gPlayer[pTarget->type-kDudePlayer1].isRunning
|
||||
&& Chance(0x8000))
|
||||
|
@ -581,9 +574,7 @@ static void cultThinkChase(DBloodActor* actor)
|
|||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (nDist < 0x3200 && abs(nDeltaAngle) < 28)
|
||||
else if (nDist < 0x3200 && abs(nDeltaAngle) < 28)
|
||||
{
|
||||
int hit = HitScan(pSprite, pSprite->z, dx, dy, 0, CLIPMASK1, 0);
|
||||
switch (hit)
|
||||
|
|
|
@ -269,7 +269,7 @@ static void gargThinkSearch(DBloodActor* actor)
|
|||
auto pXSprite = &actor->x();
|
||||
auto pSprite = &actor->s();
|
||||
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
|
||||
sub_5F15C(pSprite, pXSprite);
|
||||
aiLookForTarget(pSprite, pXSprite);
|
||||
}
|
||||
|
||||
static void gargThinkGoto(DBloodActor* actor)
|
||||
|
|
|
@ -42,25 +42,22 @@ AISTATE spidGoto = { kAiStateMove, 7, -1, 600, NULL, aiMoveForward, spidThinkGot
|
|||
AISTATE spidSearch = { kAiStateSearch, 7, -1, 1800, NULL, aiMoveForward, spidThinkSearch, &spidIdle };
|
||||
AISTATE spidBite = { kAiStateChase, 6, nSpidBiteClient, 60, NULL, NULL, NULL, &spidChase };
|
||||
AISTATE spidJump = { kAiStateChase, 8, nSpidJumpClient, 60, NULL, aiMoveForward, NULL, &spidChase };
|
||||
AISTATE spid13A92C = { kAiStateOther, 0, dword_279B50, 60, NULL, NULL, NULL, &spidIdle };
|
||||
AISTATE spidBirth = { kAiStateOther, 0, nSpidBirthClient, 60, NULL, NULL, NULL, &spidIdle };
|
||||
|
||||
static char sub_70D30(XSPRITE *pXDude, int a2, int a3)
|
||||
static char SpidPoisonPlayer(XSPRITE *pXDude, int nBlind, int max)
|
||||
{
|
||||
assert(pXDude != NULL);
|
||||
int nDude = pXDude->reference;
|
||||
spritetype *pDude = &sprite[nDude];
|
||||
if (IsPlayerSprite(pDude))
|
||||
{
|
||||
a2 <<= 4;
|
||||
a3 <<= 4;
|
||||
if (IsPlayerSprite(pDude))
|
||||
nBlind <<= 4;
|
||||
max <<= 4;
|
||||
PLAYER *pPlayer = &gPlayer[pDude->type-kDudePlayer1];
|
||||
if (pPlayer->blindEffect < max)
|
||||
{
|
||||
PLAYER *pPlayer = &gPlayer[pDude->type-kDudePlayer1];
|
||||
if (a3 > pPlayer->blindEffect)
|
||||
{
|
||||
pPlayer->blindEffect = ClipHigh(pPlayer->blindEffect+a2, a3);
|
||||
return 1;
|
||||
}
|
||||
pPlayer->blindEffect = ClipHigh(pPlayer->blindEffect+nBlind, max);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -93,11 +90,11 @@ void SpidBiteSeqCallback(int, DBloodActor* actor)
|
|||
break;
|
||||
case kDudeSpiderRed:
|
||||
actFireVector(pSprite, 0, 0, dx, dy, dz, kVectorSpiderBite);
|
||||
if (Chance(0x5000)) sub_70D30(pXTarget, 4, 16);
|
||||
if (Chance(0x5000)) SpidPoisonPlayer(pXTarget, 4, 16);
|
||||
break;
|
||||
case kDudeSpiderBlack:
|
||||
actFireVector(pSprite, 0, 0, dx, dy, dz, kVectorSpiderBite);
|
||||
sub_70D30(pXTarget, 8, 16);
|
||||
SpidPoisonPlayer(pXTarget, 8, 16);
|
||||
break;
|
||||
case kDudeSpiderMother: {
|
||||
actFireVector(pSprite, 0, 0, dx, dy, dz, kVectorSpiderBite);
|
||||
|
@ -106,9 +103,9 @@ void SpidBiteSeqCallback(int, DBloodActor* actor)
|
|||
dy += Random2(2000);
|
||||
dz += Random2(2000);
|
||||
actFireVector(pSprite, 0, 0, dx, dy, dz, kVectorSpiderBite);
|
||||
sub_70D30(pXTarget, 8, 16);
|
||||
}
|
||||
SpidPoisonPlayer(pXTarget, 8, 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +138,7 @@ void SpidJumpSeqCallback(int, DBloodActor* actor)
|
|||
}
|
||||
}
|
||||
|
||||
void sub_71370(int, DBloodActor* actor)
|
||||
void SpidBirthSeqCallback(int, DBloodActor* actor)
|
||||
{
|
||||
XSPRITE* pXSprite = &actor->x();
|
||||
spritetype* pSprite = &actor->s();
|
||||
|
@ -249,7 +246,7 @@ static void spidThinkChase(DBloodActor* actor)
|
|||
if (nDist < 0x733 && nDist > 0x399 && abs(nDeltaAngle) < 85)
|
||||
aiNewState(actor, &spidJump);
|
||||
else if (Chance(0x8000))
|
||||
aiNewState(actor, &spid13A92C);
|
||||
aiNewState(actor, &spidBirth);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -313,7 +313,7 @@ extern AISTATE spidGoto;
|
|||
extern AISTATE spidSearch;
|
||||
extern AISTATE spidBite;
|
||||
extern AISTATE spidJump;
|
||||
extern AISTATE spid13A92C;
|
||||
extern AISTATE spidBirth;
|
||||
|
||||
extern AISTATE tchernobogIdle;
|
||||
extern AISTATE tchernobogSearch;
|
||||
|
|
|
@ -104,6 +104,13 @@ const GENDUDESND gCustomDudeSnd[] = {
|
|||
{ 9008, 0, 17, false, false }, // transforming in other dude
|
||||
};
|
||||
|
||||
// for kModernThingThrowableRock
|
||||
short gCustomDudeDebrisPics[6] = {
|
||||
|
||||
2406, 2280, 2185, 2155, 2620, 3135
|
||||
|
||||
};
|
||||
|
||||
GENDUDEEXTRA gGenDudeExtra[kMaxSprites]; // savegame handling in ai.cpp
|
||||
|
||||
static void forcePunch(DBloodActor* actor)
|
||||
|
@ -318,12 +325,7 @@ static void ThrowThing(DBloodActor* actor, bool impact)
|
|||
impact = true;
|
||||
break;
|
||||
case kModernThingThrowableRock:
|
||||
int sPics[6];
|
||||
sPics[0] = 2406; sPics[1] = 2280;
|
||||
sPics[2] = 2185; sPics[3] = 2155;
|
||||
sPics[4] = 2620; sPics[5] = 3135;
|
||||
|
||||
pThing->picnum = sPics[Random(5)];
|
||||
pThing->picnum = gCustomDudeDebrisPics[Random(5)];
|
||||
pThing->xrepeat = pThing->yrepeat = 24 + Random(42);
|
||||
pThing->cstat |= 0x0001;
|
||||
pThing->pal = 5;
|
||||
|
@ -380,7 +382,7 @@ static void unicultThinkSearch(DBloodActor* actor)
|
|||
|
||||
//viewSetSystemMessage("IN SEARCH");
|
||||
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
|
||||
sub_5F15C(pSprite, pXSprite);
|
||||
aiLookForTarget(pSprite, pXSprite);
|
||||
}
|
||||
|
||||
static void unicultThinkGoto(DBloodActor* actor)
|
||||
|
@ -617,7 +619,7 @@ static void unicultThinkChase(DBloodActor* actor)
|
|||
mdist = 2500;
|
||||
fallthrough__;
|
||||
case kMissileFireball:
|
||||
case kMissileFireballNapam:
|
||||
case kMissileFireballNapalm:
|
||||
case kMissileFireballCerberus:
|
||||
case kMissileFireballTchernobog:
|
||||
if (mdist == defDist) mdist = 3000;
|
||||
|
@ -832,7 +834,7 @@ static void unicultThinkChase(DBloodActor* actor)
|
|||
case kMissileTeslaAlt:
|
||||
case kMissileFlareAlt:
|
||||
case kMissileFireball:
|
||||
case kMissileFireballNapam:
|
||||
case kMissileFireballNapalm:
|
||||
case kMissileFireballCerberus:
|
||||
case kMissileFireballTchernobog: {
|
||||
// allow attack if dude is far from object, but target is close to it
|
||||
|
@ -1326,7 +1328,7 @@ void scaleDamage(XSPRITE* pXSprite) {
|
|||
curScale[kDmgSpirit] = 32 + Random(18);
|
||||
break;
|
||||
case kMissileFireball:
|
||||
case kMissileFireballNapam:
|
||||
case kMissileFireballNapalm:
|
||||
case kMissileFireballCerberus:
|
||||
case kMissileFireballTchernobog:
|
||||
curScale[kDmgBurn] = 50;
|
||||
|
@ -1624,19 +1626,23 @@ bool doExplosion(spritetype* pSprite, int nType) {
|
|||
|
||||
// this function allows to spawn new custom dude and inherit spawner settings,
|
||||
// so custom dude can have different weapons, hp and so on...
|
||||
spritetype* genDudeSpawn(spritetype* pSprite, int nDist) {
|
||||
spritetype* genDudeSpawn(XSPRITE* pXSource, spritetype* pSprite, int nDist) {
|
||||
|
||||
spritetype* pSource = pSprite; XSPRITE* pXSource = &xsprite[pSource->extra];
|
||||
spritetype* pDude = actSpawnSprite(pSprite, 6); XSPRITE* pXDude = &xsprite[pDude->extra];
|
||||
spritetype* pSource = &sprite[pXSource->reference];
|
||||
spritetype* pDude = actSpawnSprite(pSprite, kStatDude); XSPRITE* pXDude = &xsprite[pDude->extra];
|
||||
|
||||
int x, y, z = pSprite->z, nAngle = pSprite->ang, nType = kDudeModernCustom;
|
||||
|
||||
if (nDist > 0) {
|
||||
|
||||
x = pSprite->x + mulscale30r(Cos(nAngle), nDist);
|
||||
y = pSprite->y + mulscale30r(Sin(nAngle), nDist);
|
||||
|
||||
} else {
|
||||
|
||||
x = pSprite->x;
|
||||
y = pSprite->y;
|
||||
|
||||
}
|
||||
|
||||
pDude->type = nType; pDude->ang = nAngle;
|
||||
|
@ -1656,7 +1662,8 @@ spritetype* genDudeSpawn(spritetype* pSprite, int nDist) {
|
|||
pXDude->busyTime = pXSource->busyTime;
|
||||
|
||||
// inherit clipdist?
|
||||
if (pSource->clipdist > 0) pDude->clipdist = pSource->clipdist;
|
||||
if (pSource->clipdist > 0)
|
||||
pDude->clipdist = pSource->clipdist;
|
||||
|
||||
// inherit custom hp settings
|
||||
if (pXSource->data4 <= 0) pXDude->health = dudeInfo[nType - kDudeBase].startHealth << 4;
|
||||
|
@ -1665,29 +1672,29 @@ spritetype* genDudeSpawn(spritetype* pSprite, int nDist) {
|
|||
|
||||
if (pSource->flags & kModernTypeFlag1) {
|
||||
switch (pSource->type) {
|
||||
case kModernCustomDudeSpawn:
|
||||
//inherit pal?
|
||||
if (pDude->pal <= 0) pDude->pal = pSource->pal;
|
||||
case kModernCustomDudeSpawn:
|
||||
//inherit pal?
|
||||
if (pDude->pal <= 0) pDude->pal = pSource->pal;
|
||||
|
||||
// inherit spawn sprite trigger settings, so designer can count monsters.
|
||||
pXDude->txID = pXSource->txID;
|
||||
pXDude->command = pXSource->command;
|
||||
pXDude->triggerOn = pXSource->triggerOn;
|
||||
pXDude->triggerOff = pXSource->triggerOff;
|
||||
// inherit spawn sprite trigger settings, so designer can count monsters.
|
||||
pXDude->txID = pXSource->txID;
|
||||
pXDude->command = pXSource->command;
|
||||
pXDude->triggerOn = pXSource->triggerOn;
|
||||
pXDude->triggerOff = pXSource->triggerOff;
|
||||
|
||||
// inherit drop items
|
||||
pXDude->dropMsg = pXSource->dropMsg;
|
||||
// inherit drop items
|
||||
pXDude->dropMsg = pXSource->dropMsg;
|
||||
|
||||
// inherit required key so it can be dropped
|
||||
pXDude->key = pXSource->key;
|
||||
// inherit required key so it can be dropped
|
||||
pXDude->key = pXSource->key;
|
||||
|
||||
// inherit dude flags
|
||||
pXDude->dudeDeaf = pXSource->dudeDeaf;
|
||||
pXDude->dudeGuard = pXSource->dudeGuard;
|
||||
pXDude->dudeAmbush = pXSource->dudeAmbush;
|
||||
pXDude->dudeFlag4 = pXSource->dudeFlag4;
|
||||
pXDude->unused1 = pXSource->unused1;
|
||||
break;
|
||||
// inherit dude flags
|
||||
pXDude->dudeDeaf = pXSource->dudeDeaf;
|
||||
pXDude->dudeGuard = pXSource->dudeGuard;
|
||||
pXDude->dudeAmbush = pXSource->dudeAmbush;
|
||||
pXDude->dudeFlag4 = pXSource->dudeFlag4;
|
||||
pXDude->unused1 = pXSource->unused1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1697,6 +1704,7 @@ spritetype* genDudeSpawn(spritetype* pSprite, int nDist) {
|
|||
pDude->yrepeat = pSource->yrepeat;
|
||||
}
|
||||
|
||||
gKillMgr.AddNewKill(1);
|
||||
aiInitSprite(pDude);
|
||||
return pDude;
|
||||
}
|
||||
|
|
|
@ -209,7 +209,7 @@ void aiGenDudeNewState(spritetype* pSprite, AISTATE* pAIState);
|
|||
int getGenDudeMoveSpeed(spritetype* pSprite, int which, bool mul, bool shift);
|
||||
int checkAttackState(DBloodActor* actor);
|
||||
bool doExplosion(spritetype* pSprite, int nType);
|
||||
spritetype* genDudeSpawn(spritetype* pSprite, int nDist);
|
||||
spritetype* genDudeSpawn(XSPRITE* pXSource, spritetype* pSprite, int nDist);
|
||||
void genDudeTransform(spritetype* pSprite);
|
||||
void dudeLeechOperate(spritetype* pSprite, XSPRITE* pXSprite, EVENT a3);
|
||||
int getDodgeChance(spritetype* pSprite);
|
||||
|
|
|
@ -88,7 +88,7 @@ static void zombaThinkSearch(DBloodActor* actor)
|
|||
auto pXSprite = &actor->x();
|
||||
auto pSprite = &actor->s();
|
||||
aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
|
||||
sub_5F15C(pSprite, pXSprite);
|
||||
aiLookForTarget(pSprite, pXSprite);
|
||||
}
|
||||
|
||||
static void zombaThinkGoto(DBloodActor* actor)
|
||||
|
|
|
@ -70,6 +70,9 @@ static void RotateXZ(int *pX, int *, int *pZ, int ang)
|
|||
|
||||
template<typename T> tspritetype* viewInsertTSprite(spritetype* tsprite, int& spritesortcnt, int nSector, int nStatnum, T const * const pSprite)
|
||||
{
|
||||
if (spritesortcnt >= MAXSPRITESONSCREEN)
|
||||
return nullptr;
|
||||
|
||||
int nTSprite = spritesortcnt;
|
||||
tspritetype *pTSprite = &tsprite[nTSprite];
|
||||
memset(pTSprite, 0, sizeof(tspritetype));
|
||||
|
@ -95,7 +98,7 @@ template<typename T> tspritetype* viewInsertTSprite(spritetype* tsprite, int& sp
|
|||
return pTSprite;
|
||||
}
|
||||
|
||||
static const int effectDetail[] = {
|
||||
static const int effectDetail[kViewEffectMax] = {
|
||||
4, 4, 4, 4, 0, 0, 0, 0, 0, 1, 4, 4, 0, 0, 0, 1, 0, 0, 0
|
||||
};
|
||||
|
||||
|
@ -130,10 +133,37 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
if (gDetail < effectDetail[nViewEffect] || nTSprite >= MAXSPRITESONSCREEN) return NULL;
|
||||
switch (nViewEffect)
|
||||
{
|
||||
case kViewEffectSpotProgress: {
|
||||
XSPRITE* pXSprite = &xsprite[pTSprite->extra];
|
||||
int perc = (100 * pXSprite->data3) / kMaxPatrolSpotValue;
|
||||
int width = (94 * pXSprite->data3) / kMaxPatrolSpotValue;
|
||||
|
||||
int top, bottom;
|
||||
GetSpriteExtents(pTSprite, &top, &bottom);
|
||||
|
||||
auto pNSprite2 = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite2)
|
||||
break;
|
||||
|
||||
pNSprite2->picnum = 2203;
|
||||
|
||||
pNSprite2->xrepeat = width;
|
||||
pNSprite2->yrepeat = 20;
|
||||
pNSprite2->pal = 10;
|
||||
if (perc >= 75) pNSprite2->pal = 0;
|
||||
else if (perc >= 50) pNSprite2->pal = 6;
|
||||
|
||||
pNSprite2->z = top - 2048;
|
||||
pNSprite2->shade = -128;
|
||||
break;
|
||||
}
|
||||
case kViewEffectAtom:
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
int ang = (PlayClock*2048)/120;
|
||||
int nRand1 = dword_172CE0[i][0];
|
||||
int nRand2 = dword_172CE0[i][1];
|
||||
|
@ -157,6 +187,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
int top, bottom;
|
||||
GetSpriteExtents(pTSprite, &top, &bottom);
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
pNSprite->shade = -128;
|
||||
pNSprite->pal = 0;
|
||||
pNSprite->z = top;
|
||||
|
@ -170,6 +203,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectTesla:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
pNSprite->z = pTSprite->z;
|
||||
pNSprite->cstat |= 2;
|
||||
pNSprite->shade = -128;
|
||||
|
@ -181,6 +217,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectShoot:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
pNSprite->shade = -128;
|
||||
pNSprite->pal = 0;
|
||||
pNSprite->xrepeat = pNSprite->yrepeat = 64;
|
||||
|
@ -190,6 +229,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectReflectiveBall:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
pNSprite->shade = 26;
|
||||
pNSprite->pal = 0;
|
||||
pNSprite->cstat |= 2;
|
||||
|
@ -200,6 +242,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectPhase:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
int top, bottom;
|
||||
GetSpriteExtents(pTSprite, &top, &bottom);
|
||||
pNSprite->shade = 26;
|
||||
|
@ -225,6 +270,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
{
|
||||
int nSector = pTSprite->sectnum;
|
||||
auto pNSprite = viewInsertTSprite<tspritetype>(tsprite, spritesortcnt, nSector, 32767, NULL);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
int nLen = 128+(i<<7);
|
||||
int x = MulScale(nLen, Cos(nAng), 30);
|
||||
pNSprite->x = pTSprite->x + x;
|
||||
|
@ -249,6 +297,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectFlame:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
pNSprite->shade = -128;
|
||||
pNSprite->z = pTSprite->z;
|
||||
pNSprite->picnum = 908;
|
||||
|
@ -259,6 +310,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectSmokeHigh:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
int top, bottom;
|
||||
GetSpriteExtents(pTSprite, &top, &bottom);
|
||||
pNSprite->z = top;
|
||||
|
@ -275,6 +329,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectSmokeLow:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
int top, bottom;
|
||||
GetSpriteExtents(pTSprite, &top, &bottom);
|
||||
pNSprite->z = bottom;
|
||||
|
@ -291,6 +348,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectTorchHigh:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
int top, bottom;
|
||||
GetSpriteExtents(pTSprite, &top, &bottom);
|
||||
pNSprite->z = top;
|
||||
|
@ -302,6 +362,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectTorchLow:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
int top, bottom;
|
||||
GetSpriteExtents(pTSprite, &top, &bottom);
|
||||
pNSprite->z = bottom;
|
||||
|
@ -315,6 +378,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
if (r_shadows)
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
pNSprite->z = getflorzofslope(pTSprite->sectnum, pNSprite->x, pNSprite->y);
|
||||
pNSprite->shade = 127;
|
||||
pNSprite->cstat |= 2;
|
||||
|
@ -331,6 +397,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectFlareHalo:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
pNSprite->shade = -128;
|
||||
pNSprite->pal = 2;
|
||||
pNSprite->cstat |= 2;
|
||||
|
@ -343,6 +412,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectCeilGlow:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
sectortype *pSector = §or[pTSprite->sectnum];
|
||||
pNSprite->x = pTSprite->x;
|
||||
pNSprite->y = pTSprite->y;
|
||||
|
@ -359,6 +431,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectFloorGlow:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
sectortype *pSector = §or[pTSprite->sectnum];
|
||||
pNSprite->x = pTSprite->x;
|
||||
pNSprite->y = pTSprite->y;
|
||||
|
@ -376,6 +451,9 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
case kViewEffectSpear:
|
||||
{
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
pNSprite->z = pTSprite->z;
|
||||
if (gDetail > 1)
|
||||
pNSprite->cstat |= 514;
|
||||
|
@ -390,29 +468,34 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
assert(pTSprite->type >= kDudePlayer1 && pTSprite->type <= kDudePlayer8);
|
||||
PLAYER *pPlayer = &gPlayer[pTSprite->type-kDudePlayer1];
|
||||
WEAPONICON weaponIcon = gWeaponIcon[pPlayer->curWeapon];
|
||||
const int nTile = weaponIcon.nTile;
|
||||
auto& nTile = weaponIcon.nTile;
|
||||
if (nTile < 0) break;
|
||||
auto pNSprite = viewInsertTSprite(tsprite, spritesortcnt, pTSprite->sectnum, 32767, pTSprite);
|
||||
if (!pNSprite)
|
||||
break;
|
||||
|
||||
pNSprite->x = pTSprite->x;
|
||||
pNSprite->y = pTSprite->y;
|
||||
pNSprite->z = pTSprite->z-(32<<8);
|
||||
pNSprite->z -= weaponIcon.zOffset<<8; // offset up
|
||||
pNSprite->picnum = nTile;
|
||||
pNSprite->shade = pTSprite->shade;
|
||||
pNSprite->xrepeat = 32;
|
||||
pNSprite->yrepeat = 32;
|
||||
const int nVoxel = voxelIndex[nTile];
|
||||
auto& nVoxel = voxelIndex[nTile];
|
||||
if (cl_showweapon == 2 && r_voxels && nVoxel != -1)
|
||||
{
|
||||
pNSprite->ang = (gView->pSprite->ang + 512) & 2047; // always face viewer
|
||||
pNSprite->cstat |= 48;
|
||||
pNSprite->cstat &= ~8;
|
||||
pNSprite->picnum = nVoxel;
|
||||
pNSprite->z -= weaponIcon.zOffset<<8;
|
||||
const int lifeLeech = 9;
|
||||
if (pPlayer->curWeapon == lifeLeech)
|
||||
if (pPlayer->curWeapon == kWeapLifeLeech) // position lifeleech behind player
|
||||
{
|
||||
pNSprite->x -= MulScale(128, Cos(pNSprite->ang), 30);
|
||||
pNSprite->y -= MulScale(128, Sin(pNSprite->ang), 30);
|
||||
pNSprite->x += MulScale(128, Cos(gView->pSprite->ang), 30);
|
||||
pNSprite->y += MulScale(128, Sin(gView->pSprite->ang), 30);
|
||||
}
|
||||
if ((pPlayer->curWeapon == kWeapLifeLeech) || (pPlayer->curWeapon == kWeapVoodooDoll)) // make lifeleech/voodoo doll always face viewer like sprite
|
||||
pNSprite->ang = (pNSprite->ang + 512) & 2047; // offset angle 90 degrees
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -422,7 +505,7 @@ static tspritetype *viewAddEffect(spritetype* tsprite, int& spritesortcnt, int n
|
|||
|
||||
static void viewApplyDefaultPal(tspritetype *pTSprite, sectortype const *pSector)
|
||||
{
|
||||
int const nXSector = pSector->extra;
|
||||
auto& nXSector = pSector->extra;
|
||||
XSECTOR const *pXSector = nXSector >= 0 ? &xsector[nXSector] : NULL;
|
||||
if (pXSector && pXSector->color && (VanillaMode() || pSector->floorpal != 0))
|
||||
{
|
||||
|
@ -818,6 +901,12 @@ void viewProcessSprites(spritetype* tsprite, int& spritesortcnt, int32_t cX, int
|
|||
viewAddEffect(tsprite, spritesortcnt, nTSprite, kViewEffectShadow);
|
||||
}
|
||||
}
|
||||
|
||||
if (gModernMap) { // add target spot indicator for patrol dudes
|
||||
XSPRITE* pTXSprite = &xsprite[pTSprite->extra];
|
||||
if (pTXSprite->dudeFlag4 && aiInPatrolState(pTXSprite->aiState) && pTXSprite->data3 > 0 && pTXSprite->data3 <= kMaxPatrolSpotValue)
|
||||
viewAddEffect(tsprite, spritesortcnt, nTSprite, kViewEffectSpotProgress);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kStatTraps: {
|
||||
|
|
|
@ -218,7 +218,7 @@ int RFS::Open(int lumpnum)
|
|||
}
|
||||
|
||||
int fileSize = (int)hFile.GetLength();
|
||||
buffer.Resize(fileSize);
|
||||
buffer.Resize(fileSize+1);
|
||||
_ptr = buffer.Data();
|
||||
if (_ptr == NULL) {
|
||||
Printf("BARF: Not enough memory to read %d", lumpnum);
|
||||
|
@ -226,11 +226,12 @@ int RFS::Open(int lumpnum)
|
|||
}
|
||||
|
||||
hFile.Read(_ptr, fileSize);
|
||||
buffer[fileSize] = '\n';
|
||||
|
||||
_curLine = 0;
|
||||
_pUnknown2 = _ptr;
|
||||
_curChar = '\n';
|
||||
_pEnd = &_ptr[fileSize - 1];
|
||||
_pEnd = &_ptr[fileSize];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -84,7 +84,6 @@ void StartLevel(MapRecord* level, bool newgame)
|
|||
if (!level) return;
|
||||
gFrameCount = 0;
|
||||
PlayClock = 0;
|
||||
STAT_Update(0);
|
||||
EndLevel();
|
||||
inputState.ClearAllInput();
|
||||
currentLevel = level;
|
||||
|
@ -92,7 +91,7 @@ void StartLevel(MapRecord* level, bool newgame)
|
|||
if (gGameOptions.nGameType == 0)
|
||||
{
|
||||
///////
|
||||
gGameOptions.weaponsV10x = gWeaponsV10x;
|
||||
gGameOptions.weaponsV10x = cl_bloodoldweapbalance;
|
||||
///////
|
||||
}
|
||||
#if 0
|
||||
|
@ -201,6 +200,8 @@ void StartLevel(MapRecord* level, bool newgame)
|
|||
pPlayer->qavLoop = gPlayerTemp[i].qavLoop;
|
||||
pPlayer->weaponTimer = gPlayerTemp[i].weaponTimer;
|
||||
pPlayer->nextWeapon = gPlayerTemp[i].nextWeapon;
|
||||
pPlayer->qavLastTick = gPlayerTemp[i].qavLastTick;
|
||||
pPlayer->qavTimer = gPlayerTemp[i].qavTimer;
|
||||
}
|
||||
}
|
||||
PreloadCache();
|
||||
|
@ -241,6 +242,12 @@ void GameInterface::NextLevel(MapRecord *map, int skill)
|
|||
NewLevel(map, skill, false);
|
||||
}
|
||||
|
||||
int GameInterface::GetCurrentSkill()
|
||||
{
|
||||
return gGameOptions.nDifficulty;
|
||||
}
|
||||
|
||||
|
||||
void GameInterface::Ticker()
|
||||
{
|
||||
for (int i = connecthead; i >= 0; i = connectpoint2[i])
|
||||
|
|
|
@ -149,6 +149,10 @@ struct GameInterface : public ::GameInterface
|
|||
void EnterPortal(spritetype* viewer, int type) override;
|
||||
void LeavePortal(spritetype* viewer, int type) override;
|
||||
void LoadGameTextures() override;
|
||||
int GetCurrentSkill() override;
|
||||
bool IsQAVInterpTypeValid(const FString& type) override;
|
||||
void AddQAVInterpProps(const int& res_id, const FString& interptype, const bool& loopable, const TMap<int, TArray<int>>& ignoredata) override;
|
||||
void RemoveQAVInterpProps(const int& res_id) override;
|
||||
|
||||
GameStats getStats() override;
|
||||
};
|
||||
|
|
|
@ -172,17 +172,35 @@ enum {
|
|||
|
||||
// (weapons)
|
||||
kItemWeaponBase = 40,
|
||||
kItemWeaponRandom = kItemWeaponBase,
|
||||
kItemWeaponSawedoff = 41,
|
||||
kItemWeaponTommygun = 42,
|
||||
kItemWeaponFlarePistol = 43,
|
||||
kItemWeaponVoodooDoll = 44,
|
||||
kItemWeaponTeslaCannon = 45,
|
||||
kItemWeaponNapalmLauncher = 46,
|
||||
kItemWeaponPitchfork = 47,
|
||||
kItemWeaponSprayCan = 48,
|
||||
kItemWeaponTNT = 49,
|
||||
kItemWeaponLifeLeech = 50,
|
||||
kItemWeaponMax = 51,
|
||||
|
||||
// items (ammos)
|
||||
kItemAmmoBase = 60,
|
||||
kItemAmmoSprayCan = kItemAmmoBase,
|
||||
kItemAmmoTNTBundle = 62,
|
||||
kItemAmmoTNTBox = 63,
|
||||
kItemAmmoProxBombBundle = 64,
|
||||
kItemAmmoRemoteBombBundle = 65,
|
||||
kItemAmmoTrappedSoul = 66,
|
||||
kItemAmmoSawedoffFew = 67,
|
||||
kItemAmmoSawedoffBox = 68,
|
||||
kItemAmmoTommygunFew = 69,
|
||||
kAmmoItemVoodooDoll = 70,
|
||||
kItemAmmoVoodooDoll = 70,
|
||||
kItemAmmoTommygunDrum = 72,
|
||||
kItemAmmoTeslaCharge = 73,
|
||||
kItemAmmoFlares = 76,
|
||||
kItemAmmoGasolineCan = 79,
|
||||
kItemAmmoMax = 81,
|
||||
|
||||
kItemBase = 100,
|
||||
|
@ -302,7 +320,7 @@ enum {
|
|||
kMissilePukeGreen = 309,
|
||||
kMissileUnused = 310,
|
||||
kMissileArcGargoyle = 311,
|
||||
kMissileFireballNapam = 312,
|
||||
kMissileFireballNapalm = 312,
|
||||
kMissileFireballCerberus = 313,
|
||||
kMissileFireballTchernobog = 314,
|
||||
kMissileLifeLeechRegular = 315,
|
||||
|
@ -408,6 +426,9 @@ kAiStatePatrolWaitW,
|
|||
kAiStatePatrolMoveL,
|
||||
kAiStatePatrolMoveC,
|
||||
kAiStatePatrolMoveW,
|
||||
kAiStatePatrolTurnL,
|
||||
kAiStatePatrolTurnC,
|
||||
kAiStatePatrolTurnW,
|
||||
kAiStatePatrolMax,
|
||||
};
|
||||
|
||||
|
@ -446,6 +467,25 @@ enum
|
|||
kAng360 = 2048,
|
||||
};
|
||||
|
||||
// Weapon numbers
|
||||
enum
|
||||
{
|
||||
kWeapNone = 0,
|
||||
kWeapPitchFork = 1,
|
||||
kWeapFlareGun = 2,
|
||||
kWeapShotgun = 3,
|
||||
kWeapTommyGun = 4,
|
||||
kWeapNapalm = 5,
|
||||
kWeapDynamite = 6,
|
||||
kWeapSpraycan = 7,
|
||||
kWeapTeslaCannon = 8,
|
||||
kWeapLifeLeech = 9,
|
||||
kWeapVoodooDoll = 10,
|
||||
kWeapProximity = 11,
|
||||
kWeapRemote = 12,
|
||||
kWeapBeast = 13,
|
||||
};
|
||||
|
||||
// -------------------------------
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
|
|
@ -41,8 +41,7 @@ BEGIN_BLD_NS
|
|||
class CGameMenuItemQAV
|
||||
{
|
||||
public:
|
||||
int m_nX, m_nY;
|
||||
TArray<uint8_t> raw;
|
||||
QAV* data;
|
||||
int duration;
|
||||
int lastTick;
|
||||
bool bWideScreen;
|
||||
|
@ -53,24 +52,19 @@ public:
|
|||
|
||||
CGameMenuItemQAV::CGameMenuItemQAV(int a3, int a4, const char* name, bool widescreen, bool clearbackground)
|
||||
{
|
||||
m_nY = a4;
|
||||
m_nX = a3;
|
||||
bWideScreen = widescreen;
|
||||
bClearBackground = clearbackground;
|
||||
|
||||
if (name)
|
||||
{
|
||||
// NBlood read this directly from the file system cache, but let's better store the data locally for robustness.
|
||||
raw = fileSystem.LoadFile(name, 0);
|
||||
if (raw.Size() != 0)
|
||||
data = getQAV(fileSystem.GetResourceId(fileSystem.FindFile(name)));
|
||||
if (data)
|
||||
{
|
||||
auto data = (QAV*)raw.Data();
|
||||
data->nSprite = -1;
|
||||
data->x = m_nX;
|
||||
data->y = m_nY;
|
||||
//data->Preload();
|
||||
data->x = a3;
|
||||
data->y = a4;
|
||||
duration = data->duration;
|
||||
lastTick = I_GetBuildTime();
|
||||
lastTick = I_GetTime(data->ticrate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,20 +74,18 @@ void CGameMenuItemQAV::Draw(void)
|
|||
if (bClearBackground)
|
||||
twod->ClearScreen();
|
||||
|
||||
if (raw.Size() > 0)
|
||||
if (data)
|
||||
{
|
||||
auto data = (QAV*)raw.Data();
|
||||
int backFC = PlayClock;
|
||||
int currentclock = I_GetBuildTime();
|
||||
PlayClock = currentclock;
|
||||
int nTicks = currentclock - lastTick;
|
||||
lastTick = currentclock;
|
||||
duration -= nTicks;
|
||||
qavProcessTicker(data, &duration, &lastTick);
|
||||
|
||||
if (duration <= 0 || duration > data->duration)
|
||||
{
|
||||
duration = data->duration;
|
||||
}
|
||||
data->Play(data->duration - duration - nTicks, data->duration - duration, -1, NULL);
|
||||
auto currentDuration = data->duration - duration;
|
||||
auto smoothratio = I_GetTimeFrac(data->ticrate) * MaxSmoothRatio;
|
||||
|
||||
data->Play(currentDuration - data->ticksPerFrame, currentDuration, -1, NULL);
|
||||
|
||||
if (bWideScreen)
|
||||
{
|
||||
|
@ -102,15 +94,13 @@ void CGameMenuItemQAV::Draw(void)
|
|||
int backX = data->x;
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
data->Draw(data->duration - duration, 10 + kQavOrientationLeft, 0, 0, false);
|
||||
data->Draw(currentDuration, 10 + kQavOrientationLeft, 0, 0, false, smoothratio);
|
||||
data->x += 320;
|
||||
}
|
||||
data->x = backX;
|
||||
}
|
||||
else
|
||||
data->Draw(data->duration - duration, 10, 0, 0, false);
|
||||
|
||||
PlayClock = backFC;
|
||||
data->Draw(currentDuration, 10, 0, 0, false, smoothratio);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -935,7 +935,7 @@ void dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, shor
|
|||
pXSprite->Touch = bitReader.readUnsigned(1);
|
||||
pXSprite->Sight = bitReader.readUnsigned(1);
|
||||
pXSprite->Proximity = bitReader.readUnsigned(1);
|
||||
bitReader.readUnsigned(2);
|
||||
pXSprite->unused3 = bitReader.readUnsigned(2);
|
||||
pXSprite->lSkill = bitReader.readUnsigned(5);
|
||||
pXSprite->lS = bitReader.readUnsigned(1);
|
||||
pXSprite->lB = bitReader.readUnsigned(1);
|
||||
|
@ -950,7 +950,7 @@ void dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, shor
|
|||
pXSprite->medium = bitReader.readUnsigned(2);
|
||||
pXSprite->respawn = bitReader.readUnsigned(2);
|
||||
pXSprite->data4 = bitReader.readUnsigned(16);
|
||||
bitReader.readUnsigned(6);
|
||||
pXSprite->unused4 = bitReader.readUnsigned(6);
|
||||
pXSprite->lockMsg = bitReader.readUnsigned(8);
|
||||
pXSprite->health = bitReader.readUnsigned(12);
|
||||
pXSprite->dudeDeaf = bitReader.readUnsigned(1);
|
||||
|
|
|
@ -132,6 +132,8 @@ struct XSPRITE {
|
|||
uint8_t lockMsg; // Lock msg
|
||||
int8_t dodgeDir; // Dude dodge direction
|
||||
uint8_t unused1; // modern flags
|
||||
uint8_t unused3; // something about sight checks
|
||||
uint8_t unused4; // patrol turn delay
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -172,9 +172,12 @@ bool CheckProximityPoint(int nX1, int nY1, int nZ1, int nX2, int nY2, int nZ2, i
|
|||
int oY = abs(nY2-nY1)>>4;
|
||||
if (oY >= nDist)
|
||||
return 0;
|
||||
int oZ = abs(nZ2-nZ1)>>4;
|
||||
if (oZ >= nDist)
|
||||
return 0;
|
||||
if (nZ2 != nZ1)
|
||||
{
|
||||
int oZ = abs(nZ2-nZ1)>>8;
|
||||
if (oZ >= nDist)
|
||||
return 0;
|
||||
}
|
||||
if (approxDist(oX, oY) >= nDist) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -834,8 +837,12 @@ int GetClosestSectors(int nSector, int x, int y, int nDist, short *pSectors, cha
|
|||
return n;
|
||||
}
|
||||
|
||||
int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSectBit, short *walls)
|
||||
int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSectBit, short *pWalls, bool newSectCheckMethod)
|
||||
{
|
||||
// by default this function fails with sectors that linked with wide spans, or there was more than one link to the same sector. for example...
|
||||
// E6M1: throwing TNT on the stone footpath while standing on the brown road will fail due to the start/end points of the span being too far away. it'll only do damage at one end of the road
|
||||
// E1M2: throwing TNT at the double doors while standing on the train platform
|
||||
// by setting newSectCheckMethod to true these issues will be resolved
|
||||
static short pSectors[kMaxSectors];
|
||||
uint8_t sectbits[(kMaxSectors+7)>>3];
|
||||
memset(sectbits, 0, sizeof(sectbits));
|
||||
|
@ -848,36 +855,73 @@ int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSect
|
|||
memset(pSectBit, 0, (kMaxSectors+7)>>3);
|
||||
SetBitString(pSectBit, nSector);
|
||||
}
|
||||
while (i < n)
|
||||
while (i < n) // scan through sectors
|
||||
{
|
||||
int nCurSector = pSectors[i];
|
||||
int nStartWall = sector[nCurSector].wallptr;
|
||||
int nEndWall = nStartWall + sector[nCurSector].wallnum;
|
||||
walltype *pWall = &wall[nStartWall];
|
||||
for (int j = nStartWall; j < nEndWall; j++, pWall++)
|
||||
const int nCurSector = pSectors[i];
|
||||
const int nStartWall = sector[nCurSector].wallptr;
|
||||
const int nEndWall = nStartWall + sector[nCurSector].wallnum;
|
||||
for (int j = nStartWall; j < nEndWall; j++) // scan each wall of current sector for new sectors
|
||||
{
|
||||
int nNextSector = pWall->nextsector;
|
||||
if (nNextSector < 0)
|
||||
const walltype *pWall = &wall[j];
|
||||
const int nNextSector = pWall->nextsector;
|
||||
if (nNextSector < 0) // if next wall isn't linked to a sector, skip
|
||||
continue;
|
||||
if (TestBitString(sectbits, nNextSector))
|
||||
if (TestBitString(sectbits, nNextSector)) // if we've already checked this sector, skip
|
||||
continue;
|
||||
SetBitString(sectbits, nNextSector);
|
||||
if (CheckProximityWall(wall[j].point2, x, y, nDist))
|
||||
bool setSectBit = true;
|
||||
bool withinRange = CheckProximityWall(pWall->point2, x, y, nDist);
|
||||
if (newSectCheckMethod && !withinRange) // if range check failed, try comparing midpoints/subdivides of wall span
|
||||
{
|
||||
for (int k = (j+1); k < nEndWall; k++) // scan through the rest of the sector's walls
|
||||
{
|
||||
if (wall[k].nextsector == nNextSector) // if the next walls still reference the sector, then don't flag the sector as checked (yet)
|
||||
{
|
||||
setSectBit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const int nWallA = j;
|
||||
const int nWallB = wall[nWallA].point2;
|
||||
int x1 = wall[nWallA].x, y1 = wall[nWallA].y;
|
||||
int x2 = wall[nWallB].x, y2 = wall[nWallB].y;
|
||||
int nLength = approxDist(x1-x2, y1-y2);
|
||||
const int nDist2 = (nDist+(nDist>>1))<<4;
|
||||
nLength = ClipRange(nLength / nDist2, 1, 4); // never split more than 4 times
|
||||
for (int k = 0; true; k++) // subdivide span into smaller chunks towards direction
|
||||
{
|
||||
const int xcenter = (x1+x2)>>1, ycenter = (y1+y2)>>1;
|
||||
withinRange = CheckProximityPoint(xcenter, ycenter, 0, x, y, 0, nDist);
|
||||
if (withinRange)
|
||||
break;
|
||||
if (k == (nLength-1)) // reached end
|
||||
break;
|
||||
const bool bDir = approxDist(x-x1, y-y1) < approxDist(x-x2, y-y2);
|
||||
if (bDir) // step closer and check again
|
||||
x2 = xcenter, y2 = ycenter;
|
||||
else
|
||||
x1 = xcenter, y1 = ycenter;
|
||||
}
|
||||
}
|
||||
if (withinRange) // if new sector is within range, set to current sector and test walls
|
||||
{
|
||||
setSectBit = true; // sector is within range, set as checked
|
||||
if (pSectBit)
|
||||
SetBitString(pSectBit, nNextSector);
|
||||
pSectors[n++] = nNextSector;
|
||||
if (walls && pWall->extra > 0)
|
||||
if (pWalls && pWall->extra > 0)
|
||||
{
|
||||
XWALL *pXWall = &xwall[pWall->extra];
|
||||
if (pXWall->triggerVector && !pXWall->isTriggered && !pXWall->state)
|
||||
walls[m++] = j;
|
||||
pWalls[m++] = j;
|
||||
}
|
||||
}
|
||||
if (setSectBit)
|
||||
SetBitString(sectbits, nNextSector);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (walls) walls[m] = -1;
|
||||
pSectors[n] = -1;
|
||||
if (pWalls) pWalls[m] = -1;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ void GetZRangeAtXYZ(int x, int y, int z, int nSector, int *ceilZ, int *ceilHit,
|
|||
int GetDistToLine(int x1, int y1, int x2, int y2, int x3, int y3);
|
||||
unsigned int ClipMove(int *x, int *y, int *z, int *nSector, int xv, int yv, int wd, int cd, int fd, unsigned int nMask);
|
||||
int GetClosestSectors(int nSector, int x, int y, int nDist, short *pSectors, char *pSectBit);
|
||||
int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSectBit, short *affx = nullptr);
|
||||
int GetClosestSpriteSectors(int nSector, int x, int y, int nDist, uint8_t *pSectBit, short *pWalls = nullptr, bool newSectCheckMethod = false);
|
||||
int picWidth(short nPic, short repeat);
|
||||
int picHeight(short nPic, short repeat);
|
||||
|
||||
|
|
|
@ -39,8 +39,4 @@ bool gInfiniteAmmo;
|
|||
int32_t gDeliriumBlur = 1;
|
||||
bool gFogMode = false;
|
||||
|
||||
//////////
|
||||
int gWeaponsV10x;
|
||||
/////////
|
||||
|
||||
END_BLD_NS
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue