Merge pull request #69 from madame-rachelle/gz2

gzdoom update (?)
This commit is contained in:
Nash Muhandes 2024-04-18 00:50:59 +08:00 committed by GitHub
commit b96bc845d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 691 additions and 451 deletions

1
.gitignore vendored
View file

@ -31,3 +31,4 @@
/build_vc2019-64
/build_vc2019-32
/build__
gzdoom-crash.log

View file

@ -294,6 +294,21 @@ bool FSerializer::BeginObject(const char *name)
//
//==========================================================================
bool FSerializer::HasKey(const char* name)
{
if (isReading())
{
return r->FindKey(name) != nullptr;
}
return false;
}
//==========================================================================
//
//
//
//==========================================================================
bool FSerializer::HasObject(const char* name)
{
if (isReading())

View file

@ -91,6 +91,7 @@ public:
void ReadObjects(bool hubtravel);
bool BeginObject(const char *name);
void EndObject();
bool HasKey(const char* name);
bool HasObject(const char* name);
bool BeginArray(const char *name);
void EndArray();
@ -245,6 +246,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI
FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def);
FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def);
FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &mo, struct ModelOverride *def);
FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverride &mo, struct AnimModelOverride *def);
FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def);
FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval);
@ -259,6 +261,16 @@ FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **)
return arc;
}
template<class A, class B>
FSerializer &Serialize(FSerializer &arc, const char *key, std::pair<A, B> &value, std::pair<A, B> *def)
{
arc.BeginObject(key);
Serialize(arc, "first", value.first, def ? &def->first : nullptr);
Serialize(arc, "second", value.second, def ? &def->second : nullptr);
arc.EndObject();
return arc;
}
template<class T, class TT>
FSerializer &Serialize(FSerializer &arc, const char *key, TArray<T, TT> &value, TArray<T, TT> *def)
{

View file

@ -36,6 +36,18 @@
#include <string.h>
#include <vector>
#ifndef _WIN32
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <fnmatch.h>
#include <sys/stat.h>
#include <dirent.h>
#endif
namespace FileSys {
enum
@ -63,14 +75,6 @@ enum
#ifndef _WIN32
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <fnmatch.h>
#include <sys/stat.h>
#include <dirent.h>
struct findstate_t
{
std::string path;

View file

@ -43,8 +43,6 @@
#include "texturemanager.h"
#include "modelrenderer.h"
TArray<FString> savedModelFiles;
TDeletingArray<FModel*> Models;
TArray<FSpriteModelFrame> SpriteModelFrames;
TMap<void*, FSpriteModelFrame> BaseSpriteModelFrames;
@ -160,7 +158,7 @@ unsigned FindModel(const char * path, const char * modelfile, bool silent)
for(unsigned i = 0; i< Models.Size(); i++)
{
if (!Models[i]->mFileName.CompareNoCase(fullname)) return i;
if (Models[i]->mFileName.CompareNoCase(fullname) == 0) return i;
}
auto len = fileSystem.FileLength(lump);
@ -236,6 +234,7 @@ unsigned FindModel(const char * path, const char * modelfile, bool silent)
}
// The vertex buffer cannot be initialized here because this gets called before OpenGL is initialized
model->mFileName = fullname;
model->mFilePath = {path, modelfile};
return Models.Push(model);
}

View file

@ -18,7 +18,7 @@ struct FSpriteModelFrame;
FTextureID LoadSkin(const char* path, const char* fn);
void FlushModels();
extern TArray<FString> savedModelFiles;
extern TDeletingArray<FModel*> Models;
extern TArray<FSpriteModelFrame> SpriteModelFrames;
extern TMap<void*, FSpriteModelFrame> BaseSpriteModelFrames;
@ -76,6 +76,7 @@ enum EFrameError
class FModel
{
public:
FModel();
virtual ~FModel();
@ -100,7 +101,9 @@ public:
void DestroyVertexBuffer();
bool hasSurfaces = false;
FString mFileName;
std::pair<FString, FString> mFilePath;
FSpriteModelFrame *baseFrame;
private:

View file

@ -164,6 +164,7 @@ FVoxel *R_LoadKVX(int lumpnum)
auto lump = fileSystem.ReadFile(lumpnum); // FileData adds an extra 0 byte to the end.
auto rawvoxel = lump.bytes();
int voxelsize = (int)(lump.size());
if (voxelsize <= 768 + 4) return nullptr;
// Oh, KVX, why couldn't you have a proper header? We'll just go through
// and collect each MIP level, doing lots of range checking, and if the

View file

@ -363,54 +363,49 @@ size_t DObject::PropagateMark()
const PClass *info = GetClass();
if (!PClass::bShutdown)
{
const size_t *offsets = info->FlatPointers;
if (offsets == NULL)
if (info->FlatPointers == nullptr)
{
const_cast<PClass *>(info)->BuildFlatPointers();
offsets = info->FlatPointers;
}
while (*offsets != ~(size_t)0)
{
GC::Mark((DObject **)((uint8_t *)this + *offsets));
offsets++;
info->BuildFlatPointers();
assert(info->FlatPointers);
}
offsets = info->ArrayPointers;
if (offsets == NULL)
for(size_t i = 0; i < info->FlatPointersSize; i++)
{
const_cast<PClass *>(info)->BuildArrayPointers();
offsets = info->ArrayPointers;
GC::Mark((DObject **)((uint8_t *)this + info->FlatPointers[i].first));
}
while (*offsets != ~(size_t)0)
if (info->ArrayPointers == nullptr)
{
auto aray = (TArray<DObject*>*)((uint8_t *)this + *offsets);
info->BuildArrayPointers();
assert(info->ArrayPointers);
}
for(size_t i = 0; i < info->ArrayPointersSize; i++)
{
auto aray = (TArray<DObject*>*)((uint8_t *)this + info->ArrayPointers[i].first);
for (auto &p : *aray)
{
GC::Mark(&p);
}
offsets++;
}
if (info->MapPointers == nullptr)
{
const std::pair<size_t,PType *> *maps = info->MapPointers;
if (maps == NULL)
{
const_cast<PClass *>(info)->BuildMapPointers();
maps = info->MapPointers;
}
while (maps->first != ~(size_t)0)
{
if(maps->second->RegType == REGT_STRING)
{ // FString,DObject*
PropagateMarkMap((ZSMap<FString,DObject*>*)((uint8_t *)this + maps->first));
}
else
{ // uint32_t,DObject*
PropagateMarkMap((ZSMap<uint32_t,DObject*>*)((uint8_t *)this + maps->first));
}
maps++;
}
info->BuildMapPointers();
assert(info->MapPointers);
}
for(size_t i = 0; i < info->MapPointersSize; i++)
{
PMap * type = static_cast<PMap*>(info->MapPointers[i].second);
if(type->KeyType->RegType == REGT_STRING)
{ // FString,DObject*
PropagateMarkMap((ZSMap<FString,DObject*>*)((uint8_t *)this + info->MapPointers[i].first));
}
else
{ // uint32_t,DObject*
PropagateMarkMap((ZSMap<uint32_t,DObject*>*)((uint8_t *)this + info->MapPointers[i].first));
}
}
return info->Size;
}
@ -423,46 +418,116 @@ size_t DObject::PropagateMark()
//
//==========================================================================
size_t DObject::PointerSubstitution (DObject *old, DObject *notOld)
template<typename M>
static void MapPointerSubstitution(M *map, size_t &changed, DObject *old, DObject *notOld, const bool shouldSwap)
{
TMapIterator<typename M::KeyType, DObject*> it(*map);
typename M::Pair * p;
while(it.NextPair(p))
{
if (p->Value == old)
{
if (shouldSwap)
{
p->Value = notOld;
changed++;
}
else if (p->Value != nullptr)
{
p->Value = nullptr;
changed++;
}
}
}
}
size_t DObject::PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail)
{
const PClass *info = GetClass();
const size_t *offsets = info->FlatPointers;
size_t changed = 0;
if (offsets == NULL)
if (info->FlatPointers == nullptr)
{
const_cast<PClass *>(info)->BuildFlatPointers();
offsets = info->FlatPointers;
}
while (*offsets != ~(size_t)0)
{
if (*(DObject **)((uint8_t *)this + *offsets) == old)
{
*(DObject **)((uint8_t *)this + *offsets) = notOld;
changed++;
}
offsets++;
info->BuildFlatPointers();
assert(info->FlatPointers);
}
offsets = info->ArrayPointers;
if (offsets == NULL)
for(size_t i = 0; i < info->FlatPointersSize; i++)
{
const_cast<PClass *>(info)->BuildArrayPointers();
offsets = info->ArrayPointers;
size_t offset = info->FlatPointers[i].first;
auto& obj = *(DObject**)((uint8_t*)this + offset);
if (obj == old)
{
// If a pointer's type is null, that means it's native and anything native is safe to swap
// around due to its inherit type expansiveness.
if (info->FlatPointers[i].second == nullptr || notOld->IsKindOf(info->FlatPointers[i].second->PointedClass()))
{
obj = notOld;
changed++;
}
else if (nullOnFail && obj != nullptr)
{
obj = nullptr;
changed++;
}
}
}
while (*offsets != ~(size_t)0)
if (info->ArrayPointers == nullptr)
{
auto aray = (TArray<DObject*>*)((uint8_t *)this + *offsets);
info->BuildArrayPointers();
assert(info->ArrayPointers);
}
for(size_t i = 0; i < info->ArrayPointersSize; i++)
{
const bool isType = notOld->IsKindOf(static_cast<PObjectPointer*>(info->ArrayPointers[i].second->ElementType)->PointedClass());
if (!isType && !nullOnFail)
continue;
auto aray = (TArray<DObject*>*)((uint8_t*)this + info->ArrayPointers[i].first);
for (auto &p : *aray)
{
if (p == old)
{
p = notOld;
changed++;
if (isType)
{
p = notOld;
changed++;
}
else if (p != nullptr)
{
p = nullptr;
changed++;
}
}
}
offsets++;
}
if (info->MapPointers == nullptr)
{
info->BuildMapPointers();
assert(info->MapPointers);
}
for(size_t i = 0; i < info->MapPointersSize; i++)
{
PMap * type = static_cast<PMap*>(info->MapPointers[i].second);
const bool isType = notOld->IsKindOf(static_cast<PObjectPointer*>(type->ValueType)->PointedClass());
if (!isType && !nullOnFail)
continue;
if(type->KeyType->RegType == REGT_STRING)
{ // FString,DObject*
MapPointerSubstitution((ZSMap<FString,DObject*>*)((uint8_t *)this + info->MapPointers[i].first), changed, old, notOld, isType);
}
else
{ // uint32_t,DObject*
MapPointerSubstitution((ZSMap<uint32_t,DObject*>*)((uint8_t *)this + info->MapPointers[i].first), changed, old, notOld, isType);
}
}
return changed;
}

View file

@ -246,7 +246,7 @@ public:
inline int* IntArray(FName field);
// This is only needed for swapping out PlayerPawns and absolutely nothing else!
virtual size_t PointerSubstitution (DObject *old, DObject *notOld);
virtual size_t PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail);
PClass *GetClass() const
{

View file

@ -80,9 +80,7 @@ DEFINE_GLOBAL(WP_NOCHANGE);
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// A harmless non-nullptr FlatPointer for classes without pointers.
static const size_t TheEnd = ~(size_t)0;
static const std::pair<size_t,PType *> TheMapEnd = {~(size_t)0 , nullptr};
static const std::pair<size_t,PType *> TheEnd = {~(size_t)0 , nullptr};
//==========================================================================
//
@ -768,75 +766,81 @@ PSymbol *PClass::FindSymbol(FName symname, bool searchparents) const
//
//==========================================================================
void PClass::BuildFlatPointers ()
void PClass::BuildFlatPointers() const
{
using pairType = std::pair<size_t, PObjectPointer *>;
if (FlatPointers != nullptr)
{ // Already built: Do nothing.
return;
}
else if (ParentClass == nullptr)
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
if (Pointers == nullptr)
{ // No pointers: Make FlatPointers a harmless non-nullptr.
FlatPointers = &TheEnd;
}
else
{
FlatPointers = Pointers;
}
}
else
{
ParentClass->BuildFlatPointers ();
TArray<size_t> ScriptPointers;
// Collect all pointers in scripted fields. These are not part of the Pointers list.
for (auto field : Fields)
TArray<pairType> NativePointers;
if (Pointers != nullptr)
{
if (!(field->Flags & VARF_Native))
for (size_t i = 0; Pointers[i] != ~(size_t)0; i++)
{
field->Type->SetPointer(Defaults, unsigned(field->Offset), &ScriptPointers);
NativePointers.Push({Pointers[i], nullptr}); // native pointers have a null type
}
}
if (Pointers == nullptr && ScriptPointers.Size() == 0)
{ // No new pointers: Just use the same FlatPointers as the parent.
FlatPointers = ParentClass->FlatPointers;
if (ParentClass == nullptr)
{ // No parent (i.e. DObject): FlatPointers is the same as Pointers.
if (NativePointers.Size() == 0)
{ // No pointers: Make FlatPointers a harmless non-nullptr.
FlatPointers = (pairType*)(&TheEnd);
FlatPointersSize = 0;
}
else
{
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * NativePointers.Size());
memcpy(flat, NativePointers.Data(), sizeof(pairType) * NativePointers.Size());
FlatPointers = flat;
FlatPointersSize = NativePointers.Size();
}
}
else
{ // New pointers: Create a new FlatPointers array and add them.
int numPointers, numSuperPointers;
{
ParentClass->BuildFlatPointers();
if (Pointers != nullptr)
TArray<pairType> ScriptPointers;
// Collect all pointers in scripted fields. These are not part of the Pointers list.
for (auto field : Fields)
{
// Count pointers defined by this class.
for (numPointers = 0; Pointers[numPointers] != ~(size_t)0; numPointers++)
if (!(field->Flags & VARF_Native))
{
field->Type->SetPointer(Defaults, unsigned(field->Offset), &ScriptPointers);
}
}
else numPointers = 0;
// Count pointers defined by superclasses.
for (numSuperPointers = 0; ParentClass->FlatPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++)
{ }
if (NativePointers.Size() == 0 && ScriptPointers.Size() == 0)
{ // No new pointers: Just use the same FlatPointers as the parent.
FlatPointers = ParentClass->FlatPointers;
FlatPointersSize = ParentClass->FlatPointersSize;
}
else
{ // New pointers: Create a new FlatPointers array and add them.
// Concatenate them into a new array
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->FlatPointersSize + NativePointers.Size() + ScriptPointers.Size()));
// Concatenate them into a new array
size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numPointers + numSuperPointers + ScriptPointers.Size() + 1));
if (numSuperPointers > 0)
{
memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers);
if (ParentClass->FlatPointersSize > 0)
{
memcpy (flat, ParentClass->FlatPointers, sizeof(pairType) * ParentClass->FlatPointersSize);
}
if (NativePointers.Size() > 0)
{
memcpy(flat + ParentClass->FlatPointersSize, NativePointers.Data(), sizeof(pairType) * NativePointers.Size());
}
if (ScriptPointers.Size() > 0)
{
memcpy(flat + ParentClass->FlatPointersSize + NativePointers.Size(), &ScriptPointers[0], sizeof(pairType) * ScriptPointers.Size());
}
FlatPointers = flat;
FlatPointersSize = ParentClass->FlatPointersSize + NativePointers.Size() + ScriptPointers.Size();
}
if (numPointers > 0)
{
memcpy(flat + numSuperPointers, Pointers, sizeof(size_t)*numPointers);
}
if (ScriptPointers.Size() > 0)
{
memcpy(flat + numSuperPointers + numPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size());
}
flat[numSuperPointers + numPointers + ScriptPointers.Size()] = ~(size_t)0;
FlatPointers = flat;
}
}
}
@ -849,21 +853,24 @@ void PClass::BuildFlatPointers ()
//
//==========================================================================
void PClass::BuildArrayPointers()
void PClass::BuildArrayPointers() const
{
using pairType = std::pair<size_t, PDynArray *>;
if (ArrayPointers != nullptr)
{ // Already built: Do nothing.
return;
}
else if (ParentClass == nullptr)
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
ArrayPointers = &TheEnd;
{ // No parent (i.e. DObject): Make ArrayPointers a harmless non-nullptr.
ArrayPointers = (pairType*)(&TheEnd);
ArrayPointersSize = 0;
}
else
{
ParentClass->BuildArrayPointers();
TArray<size_t> ScriptPointers;
TArray<pairType> ScriptPointers;
// Collect all arrays to pointers in scripted fields.
for (auto field : Fields)
@ -877,28 +884,24 @@ void PClass::BuildArrayPointers()
if (ScriptPointers.Size() == 0)
{ // No new pointers: Just use the same ArrayPointers as the parent.
ArrayPointers = ParentClass->ArrayPointers;
ArrayPointersSize = ParentClass->ArrayPointersSize;
}
else
{ // New pointers: Create a new FlatPointers array and add them.
int numSuperPointers;
// Count pointers defined by superclasses.
for (numSuperPointers = 0; ParentClass->ArrayPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++)
{
}
{ // New pointers: Create a new ArrayPointers array and add them.
// Concatenate them into a new array
size_t *flat = (size_t*)ClassDataAllocator.Alloc(sizeof(size_t) * (numSuperPointers + ScriptPointers.Size() + 1));
if (numSuperPointers > 0)
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->ArrayPointersSize + ScriptPointers.Size()));
if (ParentClass->ArrayPointersSize > 0)
{
memcpy(flat, ParentClass->ArrayPointers, sizeof(size_t)*numSuperPointers);
memcpy(flat, ParentClass->ArrayPointers, sizeof(pairType) * ParentClass->ArrayPointersSize);
}
if (ScriptPointers.Size() > 0)
{
memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(size_t) * ScriptPointers.Size());
memcpy(flat + ParentClass->ArrayPointersSize, ScriptPointers.Data(), sizeof(pairType) * ScriptPointers.Size());
}
flat[numSuperPointers + ScriptPointers.Size()] = ~(size_t)0;
ArrayPointers = flat;
ArrayPointersSize = ParentClass->ArrayPointersSize + ScriptPointers.Size();
}
}
}
@ -911,21 +914,24 @@ void PClass::BuildArrayPointers()
//
//==========================================================================
void PClass::BuildMapPointers()
void PClass::BuildMapPointers() const
{
using pairType = std::pair<size_t, PMap *>;
if (MapPointers != nullptr)
{ // Already built: Do nothing.
return;
}
else if (ParentClass == nullptr)
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
MapPointers = &TheMapEnd;
{ // No parent (i.e. DObject): Make MapPointers a harmless non-nullptr.
MapPointers = (pairType*)(&TheEnd);
MapPointersSize = 0;
}
else
{
ParentClass->BuildMapPointers();
TArray<std::pair<size_t,PType *>> ScriptPointers;
TArray<pairType> ScriptPointers;
// Collect all arrays to pointers in scripted fields.
for (auto field : Fields)
@ -939,28 +945,23 @@ void PClass::BuildMapPointers()
if (ScriptPointers.Size() == 0)
{ // No new pointers: Just use the same ArrayPointers as the parent.
MapPointers = ParentClass->MapPointers;
MapPointersSize = ParentClass->MapPointersSize;
}
else
{ // New pointers: Create a new FlatPointers array and add them.
int numSuperPointers;
// Count pointers defined by superclasses.
for (numSuperPointers = 0; ParentClass->MapPointers[numSuperPointers].first != ~(size_t)0; numSuperPointers++)
{
}
{ // New pointers: Create a new FlatPointers array and add them.
// Concatenate them into a new array
std::pair<size_t,PType *> *flat = (std::pair<size_t,PType *>*)ClassDataAllocator.Alloc(sizeof(std::pair<size_t,PType *>) * (numSuperPointers + ScriptPointers.Size() + 1));
if (numSuperPointers > 0)
pairType *flat = (pairType*)ClassDataAllocator.Alloc(sizeof(pairType) * (ParentClass->MapPointersSize + ScriptPointers.Size()));
if (ParentClass->MapPointersSize > 0)
{
memcpy(flat, ParentClass->MapPointers, sizeof(std::pair<size_t,PType *>)*numSuperPointers);
memcpy(flat, ParentClass->MapPointers, sizeof(pairType) * ParentClass->MapPointersSize);
}
if (ScriptPointers.Size() > 0)
{
memcpy(flat + numSuperPointers, &ScriptPointers[0], sizeof(std::pair<size_t,PType *>) * ScriptPointers.Size());
memcpy(flat + ParentClass->MapPointersSize, ScriptPointers.Data(), sizeof(pairType) * ScriptPointers.Size());
}
flat[numSuperPointers + ScriptPointers.Size()] = TheMapEnd;
MapPointers = flat;
MapPointersSize = ParentClass->MapPointersSize + ScriptPointers.Size();
}
}
}

View file

@ -27,6 +27,9 @@ class PClassType;
struct FNamespaceManager;
class PSymbol;
class PField;
class PObjectPointer;
class PDynArray;
class PMap;
enum
{
@ -53,10 +56,15 @@ public:
// Per-class information -------------------------------------
PClass *ParentClass = nullptr; // the class this class derives from
const size_t *Pointers = nullptr; // object pointers defined by this class *only*
const size_t *FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default
const size_t *ArrayPointers = nullptr; // dynamic arrays containing object pointers.
const std::pair<size_t,PType *> *MapPointers = nullptr; // maps containing object pointers.
const size_t * Pointers = nullptr; // native object pointers defined by this class *only*
mutable size_t FlatPointersSize = 0;
mutable const std::pair<size_t, PObjectPointer*> * FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default.
mutable size_t ArrayPointersSize = 0;
mutable const std::pair<size_t, PDynArray *> * ArrayPointers = nullptr; // dynamic arrays containing object pointers.
mutable size_t MapPointersSize = 0;
mutable const std::pair<size_t, PMap *> * MapPointers = nullptr; // maps containing object pointers.
uint8_t *Defaults = nullptr;
uint8_t *Meta = nullptr; // Per-class static script data
unsigned Size = sizeof(DObject);
@ -86,9 +94,11 @@ public:
PClass *CreateDerivedClass(FName name, unsigned int size, bool *newlycreated = nullptr, int fileno = 0);
void InitializeActorInfo();
void BuildFlatPointers();
void BuildArrayPointers();
void BuildMapPointers();
void BuildFlatPointers() const;
void BuildArrayPointers() const;
void BuildMapPointers() const;
void DestroySpecials(void *addr);
void DestroyMeta(void *addr);
const PClass *NativeClass() const;

View file

@ -32,6 +32,7 @@
*/
#include "i_common.h"
#include "c_cvars.h"
#include <fnmatch.h>
#include <sys/sysctl.h>
@ -40,7 +41,7 @@
#include "st_console.h"
#include "v_text.h"
EXTERN_CVAR(Bool, longsavemessages)
double PerfToSec, PerfToMillisec;
void CalculateCPUSpeed()
@ -188,7 +189,8 @@ void I_OpenShellFolder(const char* folder)
NSString *currentpath = [filemgr currentDirectoryPath];
[filemgr changeCurrentDirectoryPath:[NSString stringWithUTF8String:folder]];
Printf("Opening folder: %s\n", folder);
if (longsavemessages)
Printf("Opening folder: %s\n", folder);
std::system("open .");
[filemgr changeCurrentDirectoryPath:currentpath];
}

View file

@ -77,6 +77,7 @@ int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad
double PerfToSec, PerfToMillisec;
CVAR(Bool, con_printansi, true, CVAR_GLOBALCONFIG|CVAR_ARCHIVE);
CVAR(Bool, con_4bitansi, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE);
EXTERN_CVAR(Bool, longsavemessages)
extern FStartupScreen *StartWindow;
@ -372,13 +373,17 @@ void I_OpenShellFolder(const char* infolder)
if (!chdir(infolder))
{
Printf("Opening folder: %s\n", infolder);
if (longsavemessages)
Printf("Opening folder: %s\n", infolder);
std::system("xdg-open .");
chdir(curdir);
}
else
{
Printf("Unable to open directory '%s\n", infolder);
if (longsavemessages)
Printf("Unable to open directory '%s\n", infolder);
else
Printf("Unable to open requested directory\n");
}
free(curdir);
}

View file

@ -110,6 +110,8 @@ EXTERN_CVAR (Bool, use_mouse)
static int WheelDelta;
extern bool CursorState;
void SetCursorState(bool visible);
extern BOOL paused;
static bool noidle = false;
@ -415,7 +417,7 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_SETCURSOR:
if (!CursorState)
{
SetCursor(NULL); // turn off window cursor
SetCursorState(false); // turn off window cursor
return TRUE; // Prevent Windows from setting cursor to window class cursor
}
else

View file

@ -131,7 +131,7 @@ enum EMouseMode
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void SetCursorState(bool visible);
void SetCursorState(bool visible);
static FMouse *CreateWin32Mouse();
static FMouse *CreateDInputMouse();
static FMouse *CreateRawMouse();
@ -191,7 +191,7 @@ CUSTOM_CVAR (Int, in_mouse, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
static bool mouse_shown = true;
static void SetCursorState(bool visible)
void SetCursorState(bool visible)
{
CursorState = visible || !m_hidepointer;
if (GetForegroundWindow() == mainwindow.GetHandle())
@ -297,6 +297,12 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult)
{
BlockMouseMove = 3;
Mouse->Ungrab();
if(!mouse_shown)
{
ShowCursor(true);
mouse_shown = true;
}
}
else
{

View file

@ -113,6 +113,7 @@ static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP
EXTERN_CVAR (Bool, queryiwad);
// Used on welcome/IWAD screen.
EXTERN_CVAR(Bool, longsavemessages)
extern HANDLE StdOut;
extern bool FancyStdOut;
@ -823,13 +824,17 @@ void I_OpenShellFolder(const char* infolder)
}
else if (SetCurrentDirectoryW(WideString(infolder).c_str()))
{
Printf("Opening folder: %s\n", infolder);
if (longsavemessages)
Printf("Opening folder: %s\n", infolder);
ShellExecuteW(NULL, L"open", L"explorer.exe", L".", NULL, SW_SHOWNORMAL);
SetCurrentDirectoryW(curdir.Data());
}
else
{
Printf("Unable to open directory '%s\n", infolder);
if (longsavemessages)
Printf("Unable to open directory '%s\n", infolder);
else
Printf("Unable to open requested directory\n");
}
}

View file

@ -9542,6 +9542,8 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
auto &argflags = Function->Variants[0].ArgFlags;
auto *defaults = FnPtrCall ? nullptr : &Function->Variants[0].Implementation->DefaultArgs;
if(FnPtrCall) static_cast<VMScriptFunction*>(ctx.Function->Variants[0].Implementation)->blockJit = true;
int implicit = Function->GetImplicitArgs();
if (!CheckAccessibility(ctx.Version))

View file

@ -196,15 +196,15 @@ void PType::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset>
//
//==========================================================================
void PType::SetPointer(void *base, unsigned offset, TArray<size_t> *stroffs)
void PType::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *stroffs)
{
}
void PType::SetPointerArray(void *base, unsigned offset, TArray<size_t> *stroffs)
void PType::SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *stroffs)
{
}
void PType::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs)
void PType::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs)
{
}
@ -1575,10 +1575,10 @@ PObjectPointer::PObjectPointer(PClass *cls, bool isconst)
//
//==========================================================================
void PObjectPointer::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
void PObjectPointer::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special)
{
// Add to the list of pointers for this class.
special->Push(offset);
special->Push({offset, this});
}
//==========================================================================
@ -1706,7 +1706,7 @@ bool PClassPointer::isCompatible(PType *type)
//
//==========================================================================
void PClassPointer::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
void PClassPointer::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special)
{
}
@ -1908,7 +1908,7 @@ void PArray::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset>
//
//==========================================================================
void PArray::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
void PArray::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special)
{
for (unsigned i = 0; i < ElementCount; ++i)
{
@ -1922,7 +1922,7 @@ void PArray::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
//
//==========================================================================
void PArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *special)
void PArray::SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *special)
{
if (ElementType->isStruct() || ElementType->isDynArray())
{
@ -1939,7 +1939,7 @@ void PArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *specia
//
//==========================================================================
void PArray::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *special)
void PArray::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *special)
{
if(ElementType->isStruct() || ElementType->isMap())
{
@ -2254,12 +2254,12 @@ void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffs
//
//==========================================================================
void PDynArray::SetPointerArray(void *base, unsigned offset, TArray<size_t> *special)
void PDynArray::SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *special)
{
if (ElementType->isObjectPointer())
{
// Add to the list of pointer arrays for this class.
special->Push(offset);
special->Push({offset, this});
}
}
@ -2524,12 +2524,12 @@ void PMap::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *
//
//==========================================================================
void PMap::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *special)
void PMap::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *special)
{
if (ValueType->isObjectPointer())
{
// Add to the list of pointer arrays for this class.
special->Push(std::make_pair(offset,KeyType));
special->Push(std::make_pair(offset, this));
}
}
@ -3264,7 +3264,7 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset
//
//==========================================================================
void PStruct::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
void PStruct::SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special)
{
auto it = Symbols.GetIterator();
PSymbolTable::MapType::Pair *pair;
@ -3284,7 +3284,7 @@ void PStruct::SetPointer(void *base, unsigned offset, TArray<size_t> *special)
//
//==========================================================================
void PStruct::SetPointerArray(void *base, unsigned offset, TArray<size_t> *special)
void PStruct::SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *special)
{
auto it = Symbols.GetIterator();
PSymbolTable::MapType::Pair *pair;
@ -3304,7 +3304,7 @@ void PStruct::SetPointerArray(void *base, unsigned offset, TArray<size_t> *speci
//
//==========================================================================
void PStruct::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *special)
void PStruct::SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *special)
{
auto it = Symbols.GetIterator();
PSymbolTable::MapType::Pair *pair;

View file

@ -68,8 +68,11 @@ class PPointer;
class PClassPointer;
class PFunctionPointer;
class PArray;
class PDynArray;
class PMap;
class PStruct;
class PClassType;
class PObjectPointer;
struct ZCC_ExprConstant;
class PType : public PTypeBase
@ -129,9 +132,9 @@ public:
// initialization when the object is created and destruction when the
// object is destroyed.
virtual void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL);
virtual void SetPointer(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL);
virtual void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL);
virtual void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs = NULL);
virtual void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *ptrofs = NULL);
virtual void SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *ptrofs = NULL);
virtual void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs = NULL);
// Initialize the value, if needed (e.g. strings)
virtual void InitializeValue(void *addr, const void *def) const;
@ -455,7 +458,7 @@ public:
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) override;
void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special = NULL) override;
PClass *PointedClass() const;
};
@ -471,7 +474,7 @@ public:
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) override;
void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special = NULL) override;
bool IsMatch(intptr_t id1, intptr_t id2) const override;
void GetTypeIDs(intptr_t &id1, intptr_t &id2) const override;
};
@ -503,9 +506,9 @@ public:
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special) override;
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs = NULL) override;
void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *special) override;
void SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *ptrofs = NULL) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs = NULL) override;
};
class PStaticArray : public PArray
@ -535,7 +538,7 @@ public:
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
void InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override;
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) override;
void SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *ptrofs = NULL) override;
};
class PMap : public PCompoundType
@ -579,7 +582,7 @@ public:
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
void InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs) override;
};
@ -653,9 +656,9 @@ public:
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *specials) override;
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *special) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t,PType *>> *ptrofs) override;
void SetPointer(void *base, unsigned offset, TArray<std::pair<size_t, PObjectPointer *>> *specials) override;
void SetPointerArray(void *base, unsigned offset, TArray<std::pair<size_t, PDynArray *>> *special) override;
void SetPointerMap(void *base, unsigned offset, TArray<std::pair<size_t, PMap *>> *ptrofs) override;
};
class PPrototype : public PCompoundType

View file

@ -43,6 +43,11 @@
FSharedStringArena VMStringConstants;
static bool ShouldWrapPointer(PType * type)
{
return ((type->isStruct() && type != TypeVector2 && type != TypeVector3 && type != TypeVector4 && type != TypeQuaternion && type != TypeFVector2 && type != TypeFVector3 && type != TypeFVector4 && type != TypeFQuaternion) || type->isDynArray() || type->isMap() || type->isMapIterator());
}
int GetIntConst(FxExpression *ex, FCompileContext &ctx)
{
ex = new FxIntCast(ex, false);
@ -2049,8 +2054,17 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
} while( (t = (ZCC_Type *)t->SiblingNext) != fn->RetType);
if(auto *t = fn->Params; t != nullptr) do {
args.Push(DetermineType(outertype, field, name, t->Type, false, false));
argflags.Push(t->Flags == ZCC_Out ? VARF_Out : 0);
PType * tt = DetermineType(outertype, field, name, t->Type, false, false);
int flags = 0;
if (ShouldWrapPointer(tt))
{
tt = NewPointer(tt);
flags = VARF_Ref;
}
args.Push(tt);
argflags.Push(t->Flags == ZCC_Out ? VARF_Out|flags : flags);
} while( (t = (ZCC_FuncPtrParamDecl *) t->SiblingNext) != fn->Params);
auto proto = NewPrototype(returns,args);
@ -2550,7 +2564,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
{
auto type = DetermineType(c->Type(), p, f->Name, p->Type, false, false);
int flags = 0;
if ((type->isStruct() && type != TypeVector2 && type != TypeVector3 && type != TypeVector4 && type != TypeQuaternion && type != TypeFVector2 && type != TypeFVector3 && type != TypeFVector4 && type != TypeFQuaternion) || type->isDynArray() || type->isMap() || type->isMapIterator())
if (ShouldWrapPointer(type))
{
// Structs are being passed by pointer, but unless marked 'out' that pointer must be readonly.
type = NewPointer(type /*, !(p->Flags & ZCC_Out)*/);

View file

@ -279,6 +279,8 @@ static bool CanJit(VMScriptFunction *func)
// Asmjit has a 256 register limit. Stay safely away from it as the jit compiler uses a few for temporaries as well.
// Any function exceeding the limit will use the VM - a fair punishment to someone for writing a function so bloated ;)
if(func->blockJit) return false;
int maxregs = 200;
if (func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS < maxregs)
return true;

View file

@ -474,6 +474,8 @@ public:
VM_UBYTE NumArgs; // Number of arguments this function takes
TArray<FTypeAndOffset> SpecialInits; // list of all contents on the extra stack which require construction and destruction
bool blockJit = false; // function triggers Jit bugs, block compilation until bugs are fixed
void InitExtra(void *addr);
void DestroyExtra(void *addr);
int AllocExtraStack(PType *type);

View file

@ -654,13 +654,11 @@ void FStartScreen::NetProgress(int count)
void FStartScreen::Render(bool force)
{
static uint64_t minwaittime = 30;
auto nowtime = I_msTime();
// Do not refresh too often. This function gets called a lot more frequently than the screen can update.
#ifdef _DEBUG
if (nowtime - screen->FrameTime > 3000 || force)
#else
if (nowtime - screen->FrameTime > 30 || force)
#endif
if (nowtime - screen->FrameTime > minwaittime || force)
{
screen->FrameTime = nowtime;
screen->FrameTimeNS = I_nsTime();
@ -694,6 +692,9 @@ void FStartScreen::Render(bool force)
screen->Update();
twod->OnFrameDone();
}
auto newtime = I_msTime();
if ((newtime - nowtime) * 2.0 > minwaittime) // slow down drawing the start screen if we're on a slow GPU!
minwaittime = (newtime - nowtime) * 2.0;
}
FImageSource* CreateStartScreenTexture(FBitmap& srcdata);

View file

@ -55,6 +55,7 @@
#include <utility>
#include <iterator>
#include <algorithm>
#include <functional>
#if !defined(_WIN32)
#include <inttypes.h> // for intptr_t
@ -366,11 +367,11 @@ public:
}
template<typename Func>
bool IsSorted(Func lt)
bool IsSorted(Func &&lt)
{
for(unsigned i = 1; i < Count; i++)
{
if(lt(Array[i], Array[i-1])) return false;
if(std::invoke(lt, Array[i], Array[i-1])) return false;
}
return true;
}
@ -418,7 +419,7 @@ public:
//
// exact = false returns the closest match, to be used for, ex., insertions, exact = true returns Size() when no match, like Find does
template<typename Func>
unsigned int SortedFind(const T& item, Func lt, bool exact = true) const
unsigned int SortedFind(const T& item, Func &&lt, bool exact = true) const
{
if(Count == 0) return 0;
if(Count == 1) return lt(item, Array[0]) ? 0 : 1;
@ -430,11 +431,11 @@ public:
{
int mid = lo + ((hi - lo) / 2);
if(lt(Array[mid], item))
if(std::invoke(lt, Array[mid], item))
{
lo = mid + 1;
}
else if(lt(item, Array[mid]))
else if(std::invoke(lt, item, Array[mid]))
{
if(mid == 0) break; // prevent negative overflow due to unsigned numbers
hi = mid - 1;
@ -450,7 +451,7 @@ public:
}
else
{
return (lo == Count || lt(item, Array[lo])) ? lo : lo + 1;
return (lo == Count || std::invoke(lt, item, Array[lo])) ? lo : lo + 1;
}
}
@ -466,12 +467,24 @@ public:
}
template<class Func>
unsigned int FindEx(Func compare) const
bool Contains(const T& item, Func &&compare) const
{
unsigned int i;
for(i = 0;i < Count;++i)
{
if(std::invoke(compare, Array[i], item))
return true;
}
return false;
}
template<class Func>
unsigned int FindEx(Func &&compare) const
{
unsigned int i;
for (i = 0; i < Count; ++i)
{
if (compare(Array[i]))
if (std::invoke(compare, Array[i]))
break;
}
return i;
@ -569,9 +582,9 @@ public:
}
template<typename Func>
unsigned SortedAddUnique(const T& obj, Func lt)
unsigned SortedAddUnique(const T& obj, Func &&lt)
{
auto f = SortedFind(obj, lt, true);
auto f = SortedFind(obj, std::forward<Func>(lt), true);
if (f == Size()) Push(obj);
return f;
}
@ -591,9 +604,9 @@ public:
}
template<typename Func>
bool SortedDelete(const T& obj, Func lt)
bool SortedDelete(const T& obj, Func &&lt)
{
auto f = SortedFind(obj, lt, true);
auto f = SortedFind(obj, std::forward<Func>(lt), true);
if (f == Size())
{
Delete(f);
@ -691,9 +704,9 @@ public:
}
template<typename Func>
void SortedInsert (const T &item, Func lt)
void SortedInsert (const T &item, Func &&lt)
{
Insert (SortedFind (item, lt, false), item);
Insert (SortedFind (item, std::forward<Func>(lt), false), item);
}
void ShrinkToFit ()

View file

@ -579,6 +579,7 @@ CVAR(Flag, sv_localitems, dmflags3, DF3_LOCAL_ITEMS);
CVAR(Flag, sv_nolocaldrops, dmflags3, DF3_NO_LOCAL_DROPS);
CVAR(Flag, sv_nocoopitems, dmflags3, DF3_NO_COOP_ONLY_ITEMS);
CVAR(Flag, sv_nocoopthings, dmflags3, DF3_NO_COOP_ONLY_THINGS);
CVAR(Flag, sv_rememberlastweapon, dmflags3, DF3_REMEMBER_LAST_WEAP);
//==========================================================================
//

View file

@ -185,6 +185,7 @@ enum : unsigned
DF3_NO_LOCAL_DROPS = 1 << 3, // Drops from Actors aren't picked up locally
DF3_NO_COOP_ONLY_ITEMS = 1 << 4, // Items that only appear in co-op are disabled
DF3_NO_COOP_ONLY_THINGS = 1 << 5, // Any Actor that only appears in co-op is disabled
DF3_REMEMBER_LAST_WEAP = 1 << 6, // When respawning in co-op, keep the last used weapon out instead of switching to the best new one.
};
// [RH] Compatibility flags.

View file

@ -1606,10 +1606,20 @@ void FLevelLocals::DeathMatchSpawnPlayer (int playernum)
if (selections < 1)
I_Error ("No deathmatch starts");
bool hasSpawned = false;
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (PlayerInGame(i) && Players[i]->mo != nullptr && Players[i]->health > 0)
{
hasSpawned = true;
break;
}
}
// At level start, none of the players have mobjs attached to them,
// so we always use the random deathmatch spawn. During the game,
// though, we use whatever dmflags specifies.
if ((dmflags & DF_SPAWN_FARTHEST) && players[playernum].mo)
if ((dmflags & DF_SPAWN_FARTHEST) && hasSpawned)
spot = SelectFarthestDeathmatchSpot (selections);
else
spot = SelectRandomDeathmatchSpot (playernum, selections);
@ -2148,14 +2158,6 @@ void G_DoLoadGame ()
BackupSaveName = savename;
//Push any added models from A_ChangeModel
for (auto& smf : savedModelFiles)
{
FString modelFilePath = smf.Left(smf.LastIndexOf("/")+1);
FString modelFileName = smf.Right(smf.Len() - smf.Left(smf.LastIndexOf("/") + 1).Len());
FindModel(modelFilePath.GetChars(), modelFileName.GetChars());
}
// At this point, the GC threshold is likely a lot higher than the
// amount of memory in use, so bring it down now by starting a
// collection.

View file

@ -1715,7 +1715,7 @@ int FLevelLocals::FinishTravel ()
pawn->flags2 &= ~MF2_BLASTED;
if (oldpawn != nullptr)
{
PlayerPointerSubstitution (oldpawn, pawn);
PlayerPointerSubstitution (oldpawn, pawn, true);
oldpawn->Destroy();
}
if (pawndup != NULL)

View file

@ -1014,8 +1014,7 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload)
("scrolls", Scrolls)
("automap", automap)
("interpolator", interpolator)
("frozenstate", frozenstate)
("savedModelFiles", savedModelFiles);
("frozenstate", frozenstate);
// Hub transitions must keep the current total time

View file

@ -506,8 +506,10 @@ int FStateDefinitions::GetStateLabelIndex (FName statename)
{
return -1;
}
assert((size_t)std->State <= StateArray.Size() + 1);
return (int)((ptrdiff_t)std->State - 1);
if ((size_t)std->State <= StateArray.Size() + 1)
return (int)((ptrdiff_t)std->State - 1);
else
return -1;
}
//==========================================================================

View file

@ -139,8 +139,8 @@ class DEarthquake : public DThinker
public:
static const int DEFAULT_STAT = STAT_EARTHQUAKE;
void Construct(AActor *center, double intensityX, double intensityY, double intensityZ, int duration,
int damrad, int tremrad, FSoundID quakesfx, int flags,
double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage);
double damrad, double tremrad, FSoundID quakesfx, int flags,
double waveSpeedX, double waveSpeedY, double waveSpeedZ, double falloff, int highpoint, double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage);
void Serialize(FSerializer &arc);
void Tick ();

View file

@ -709,7 +709,7 @@ struct AnimOverride
double startFrame;
int flags = ANIMOVERRIDE_NONE;
float framerate;
double startTic; // when the animation starts if interpolating from previous animation
double startTic; // when the current animation started (changing framerates counts as restarting) (or when animation starts if interpolating from previous animation)
double switchTic; // when the animation was changed -- where to interpolate the switch from
};
@ -719,6 +719,16 @@ struct ModelOverride
TArray<FTextureID> surfaceSkinIDs;
};
struct AnimModelOverride
{
int id;
AnimModelOverride() = default;
AnimModelOverride(int i) : id(i) {}
operator int() { return id; }
};
enum EModelDataFlags
{
MODELDATA_HADMODEL = 1 << 0,
@ -729,14 +739,14 @@ class DActorModelData : public DObject
{
DECLARE_CLASS(DActorModelData, DObject);
public:
PClass * modelDef;
TArray<ModelOverride> models;
TArray<FTextureID> skinIDs;
TArray<int> animationIDs;
TArray<int> modelFrameGenerators;
int flags;
int overrideFlagsSet;
int overrideFlagsClear;
PClass * modelDef;
TArray<ModelOverride> models;
TArray<FTextureID> skinIDs;
TArray<AnimModelOverride> animationIDs;
TArray<int> modelFrameGenerators;
int flags;
int overrideFlagsSet;
int overrideFlagsClear;
AnimOverride curAnim;
AnimOverride prevAnim; // used for interpolation when switching anims
@ -1745,7 +1755,7 @@ struct FTranslatedLineTarget
bool unlinked; // found by a trace that went through an unlinked portal.
};
void PlayerPointerSubstitution(AActor* oldPlayer, AActor* newPlayer);
void PlayerPointerSubstitution(AActor* oldPlayer, AActor* newPlayer, bool removeOld);
int MorphPointerSubstitution(AActor* from, AActor* to);
#define S_FREETARGMOBJ 1

View file

@ -125,6 +125,7 @@ typedef enum
CF_INTERPVIEWANGLES = 1 << 15, // [MR] flag for interpolating view angles without interpolating the entire frame
CF_NOFOVINTERP = 1 << 16, // [B] Disable FOV interpolation when instantly zooming
CF_SCALEDNOLERP = 1 << 17, // [MR] flag for applying angles changes in the ticrate without interpolating the frame
CF_NOVIEWPOSINTERP = 1 << 18, // Disable view position interpolation.
CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths.
CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either.
CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either.

View file

@ -549,9 +549,9 @@ size_t DFraggleThinker::PropagateMark()
//
//==========================================================================
size_t DFraggleThinker::PointerSubstitution (DObject *old, DObject *notOld)
size_t DFraggleThinker::PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail)
{
size_t changed = Super::PointerSubstitution(old, notOld);
size_t changed = Super::PointerSubstitution(old, notOld, nullOnFail);
for(unsigned i=0;i<SpawnedThings.Size();i++)
{
if (SpawnedThings[i] == static_cast<AActor*>(old))

View file

@ -701,7 +701,7 @@ public:
void Tick();
void InitFunctions();
size_t PropagateMark();
size_t PointerSubstitution (DObject *old, DObject *notOld);
size_t PointerSubstitution (DObject *old, DObject *notOld, bool nullOnFail);
bool wait_finished(DRunningScript *script);
void AddRunningScript(DRunningScript *runscr);

View file

@ -51,8 +51,8 @@ IMPLEMENT_POINTERS_END
//==========================================================================
void DEarthquake::Construct(AActor *center, double intensityX, double intensityY, double intensityZ, int duration,
int damrad, int tremrad, FSoundID quakesound, int flags,
double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint,
double damrad, double tremrad, FSoundID quakesound, int flags,
double waveSpeedX, double waveSpeedY, double waveSpeedZ, double falloff, int highpoint,
double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage)
{
m_QuakeSFX = quakesound;
@ -185,7 +185,7 @@ void DEarthquake::DoQuakeDamage(DEarthquake *quake, AActor *victim, bool falloff
if (!quake || !victim) return;
dist = quake->m_Spot->Distance2D(victim, true);
dist = quake->m_Spot->Distance2D(victim);
thrustfalloff = falloff ? GetFalloff(dist, m_DamageRadius) : 1.0;
// Check if in damage radius
if (dist < m_DamageRadius && victim->Z() <= victim->floorz)
@ -355,8 +355,8 @@ int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuak
{
double dist;
if (quake->m_Flags & QF_3D) dist = quake->m_Spot->Distance3D(victim, true);
else dist = quake->m_Spot->Distance2D(victim, true);
if (quake->m_Flags & QF_3D) dist = quake->m_Spot->Distance3D(victim);
else dist = quake->m_Spot->Distance2D(victim);
if (dist < quake->m_TremorRadius)
{
@ -429,8 +429,8 @@ int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuak
//==========================================================================
bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double intensityX, double intensityY, double intensityZ, int duration,
int damrad, int tremrad, FSoundID quakesfx, int flags,
double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint,
double damrad, double tremrad, FSoundID quakesfx, int flags,
double waveSpeedX, double waveSpeedY, double waveSpeedZ, double falloff, int highpoint,
double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage)
{
AActor *center;
@ -463,7 +463,7 @@ bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double int
return res;
}
bool P_StartQuake(FLevelLocals * Level, AActor * activator, int tid, double intensity, int duration, int damrad, int tremrad, FSoundID quakesfx)
bool P_StartQuake(FLevelLocals * Level, AActor * activator, int tid, double intensity, int duration, double damrad, double tremrad, FSoundID quakesfx)
{ //Maintains original behavior by passing 0 to intensityZ, flags, and everything else after QSFX.
return P_StartQuakeXYZ(Level, activator, tid, intensity, intensity, 0, duration, damrad, tremrad, quakesfx, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0.5, 0);
}

View file

@ -3322,8 +3322,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_Quake)
PARAM_SELF_PROLOGUE(AActor);
PARAM_FLOAT (intensity);
PARAM_INT (duration);
PARAM_INT (damrad);
PARAM_INT (tremrad);
PARAM_FLOAT (damrad);
PARAM_FLOAT (tremrad);
PARAM_SOUND (sound);
P_StartQuake(self->Level, self, 0, intensity, duration, damrad, tremrad, sound);
@ -3345,14 +3345,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_QuakeEx)
PARAM_FLOAT(intensityY);
PARAM_FLOAT(intensityZ);
PARAM_INT(duration);
PARAM_INT(damrad);
PARAM_INT(tremrad);
PARAM_FLOAT(damrad);
PARAM_FLOAT(tremrad);
PARAM_SOUND(sound);
PARAM_INT(flags);
PARAM_FLOAT(mulWaveX);
PARAM_FLOAT(mulWaveY);
PARAM_FLOAT(mulWaveZ);
PARAM_INT(falloff);
PARAM_FLOAT(falloff);
PARAM_INT(highpoint);
PARAM_FLOAT(rollIntensity);
PARAM_FLOAT(rollWave);
@ -5125,11 +5125,10 @@ enum ESetAnimationFlags
{
SAF_INSTANT = 1 << 0,
SAF_LOOP = 1 << 1,
SAF_USEACTORROLL = 1 << 2,
SAF_USEACTORPITCH = 1 << 3,
SAF_NOOVERRIDE = 1 << 2,
};
void SetAnimationInternal(AActor * self, FName animName, double framerate, int startFrame, int loopFrame, int interpolateTics, int flags, double ticFrac)
void SetAnimationInternal(AActor * self, FName animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags, double ticFrac)
{
if(!self) ThrowAbortException(X_READ_NIL, "In function parameter self");
@ -5138,6 +5137,11 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
ThrowAbortException(X_OTHER, "Cannot set animation for non-decoupled actors");
}
if(!BaseSpriteModelFrames.CheckKey(self->GetClass()))
{
ThrowAbortException(X_OTHER, "Actor class is missing a MODELDEF definition or a MODELDEF BaseFrame");
}
if(interpolateTics <= 0) interpolateTics = 1;
EnsureModelData(self);
@ -5168,6 +5172,13 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
Printf("Could not find animation %s\n", animName.GetChars());
return;
}
if((flags & SAF_NOOVERRIDE) && self->modelData->curAnim.flags != ANIMOVERRIDE_NONE && self->modelData->curAnim.firstFrame == animStart)
{
//same animation as current, skip setting it
return;
}
int animEnd = mdl->FindLastFrame(animName);
if(framerate < 0)
@ -5180,18 +5191,24 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
if(startFrame >= len)
{
self->modelData->curAnim.flags = ANIMOVERRIDE_NONE;
Printf("frame %d is past the end of animation %s\n", startFrame, animName.GetChars());
Printf("frame %d (startFrame) is past the end of animation %s\n", startFrame, animName.GetChars());
return;
}
else if(loopFrame >= len)
{
self->modelData->curAnim.flags = ANIMOVERRIDE_NONE;
Printf("frame %d is past the end of animation %s\n", startFrame, animName.GetChars());
Printf("frame %d (loopFrame) is past the end of animation %s\n", startFrame, animName.GetChars());
return;
}
else if(endFrame >= len)
{
self->modelData->curAnim.flags = ANIMOVERRIDE_NONE;
Printf("frame %d (endFrame) is past the end of animation %s\n", endFrame, animName.GetChars());
return;
}
self->modelData->curAnim.firstFrame = animStart;
self->modelData->curAnim.lastFrame = animEnd - 1;
self->modelData->curAnim.lastFrame = endFrame < 0 ? animEnd - 1 : animStart + endFrame;
self->modelData->curAnim.startFrame = startFrame < 0 ? animStart : animStart + startFrame;
self->modelData->curAnim.loopFrame = loopFrame < 0 ? animStart : animStart + loopFrame;
self->modelData->curAnim.flags = (flags&SAF_LOOP) ? ANIMOVERRIDE_LOOP : 0;
@ -5208,14 +5225,14 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
}
}
void SetAnimationNative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int interpolateTics, int flags)
void SetAnimationNative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags)
{
SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, interpolateTics, flags, 1);
SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, 1);
}
void SetAnimationUINative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int interpolateTics, int flags)
void SetAnimationUINative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags)
{
SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, interpolateTics, flags, I_GetTimeFrac());
SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, I_GetTimeFrac());
}
extern double getCurrentFrame(const AnimOverride &anim, double tic);
@ -5438,57 +5455,6 @@ void ChangeModelNative(
}
}
//[SM] - We need to serialize file paths and model names so that they are pushed on loading save files. Likewise, let's not include models that were already parsed when initialized.
if (queryModel >= 0)
{
FString fullName;
fullName.Format("%s%s", modelpath.GetChars(), model.GetChars());
bool found = false;
for (auto &m : savedModelFiles)
{
if(m.CompareNoCase(fullName) == 0)
{
found = true;
break;
}
}
if(!found) for (auto &m : Models)
{
if (m->mFileName.CompareNoCase(fullName) == 0)
{
found = true;
break;
}
}
if(!found) savedModelFiles.Push(fullName);
}
//Same for animations
if (queryAnimation >= 0)
{
FString fullName;
fullName.Format("%s%s", animationpath.GetChars(), animation.GetChars());
bool found = false;
for (auto &m : savedModelFiles)
{
if(m.CompareNoCase(fullName) == 0)
{
found = true;
break;
}
}
if(!found) for (auto &m : Models)
{
if (m->mFileName.CompareNoCase(fullName) == 0)
{
found = true;
break;
}
}
if(!found) savedModelFiles.Push(fullName);
}
CleanupModelData(mobj);
return;
@ -5522,10 +5488,11 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimation, SetAnimationNative)
PARAM_FLOAT(framerate);
PARAM_INT(startFrame);
PARAM_INT(loopFrame);
PARAM_INT(endFrame);
PARAM_INT(interpolateTics);
PARAM_INT(flags);
SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, interpolateTics, flags, 1);
SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, 1);
return 0;
}
@ -5537,10 +5504,11 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationUI, SetAnimationUINative)
PARAM_FLOAT(framerate);
PARAM_INT(startFrame);
PARAM_INT(loopFrame);
PARAM_INT(endFrame);
PARAM_INT(interpolateTics);
PARAM_INT(flags);
SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, interpolateTics, flags, I_GetTimeFrac());
SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, I_GetTimeFrac());
return 0;
}

View file

@ -448,11 +448,11 @@ static void PGRA_InsertIfCloser(TMap<int, pgra_data_t>& damageGroupPos, int grou
EXTERN_CVAR(Float, splashfactor);
void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, int bombdistance, FName damagetype, int fulldamagedistance)
void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, double bombdistance, FName damagetype, double fulldamagedistance)
{
TMap<int, pgra_data_t> damageGroupPos;
double bombdistancefloat = 1. / (double)(bombdistance - fulldamagedistance);
double bombdistancefloat = 1.0 / (bombdistance - fulldamagedistance);
// now, this is not entirely correct... but sector actions still _do_ require a valid source actor to trigger anything
if (!bombspot)
@ -588,8 +588,8 @@ void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage
int damage = 0;
if (dst < bombdistance)
{
dst = clamp<double>(dst - (double)fulldamagedistance, 0, dst);
damage = (int)((double)bombdamage * (1. - dst * bombdistancefloat));
dst = clamp<double>(dst - fulldamagedistance, 0.0, dst);
damage = (int)((double)bombdamage * (1.0 - dst * bombdistancefloat));
if (bombsource == bombspot)
damage = (int)(damage * splashfactor);
}
@ -661,8 +661,8 @@ void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage
int damage = 0;
if (dst < bombdistance)
{
dst = clamp<double>(dst - (double)fulldamagedistance, 0, dst);
damage = (int)((double)bombdamage * (1. - dst * bombdistancefloat));
dst = clamp<double>(dst - fulldamagedistance, 0.0, dst);
damage = (int)((double)bombdamage * (1.0 - dst * bombdistancefloat));
if (bombsource == bombspot)
damage = (int)(damage * splashfactor);
}
@ -950,9 +950,9 @@ DEFINE_ACTION_FUNCTION(FDestructible, GeometryRadiusAttack)
PARAM_OBJECT(bombspot, AActor);
PARAM_OBJECT(bombsource, AActor);
PARAM_INT(bombdamage);
PARAM_INT(bombdistance);
PARAM_FLOAT(bombdistance);
PARAM_NAME(damagetype);
PARAM_INT(fulldamagedistance);
PARAM_FLOAT(fulldamagedistance);
P_GeometryRadiusAttack(bombspot, bombsource, bombdamage, bombdistance, damagetype, fulldamagedistance);
return 0;
}

View file

@ -34,7 +34,7 @@ void P_DamageSector(sector_t* sector, AActor* source, int damage, FName damagety
void P_DamageLinedef(line_t* line, AActor* source, int damage, FName damagetype, int side, DVector3 position, bool isradius, bool dogroups);
void P_GeometryLineAttack(FTraceResults& trace, AActor* thing, int damage, FName damageType);
void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, int bombdistance, FName damagetype, int fulldamagedistance);
void P_GeometryRadiusAttack(AActor* bombspot, AActor* bombsource, int bombdamage, double bombdistance, FName damagetype, double fulldamagedistance);
bool P_ProjectileHitLinedef(AActor* projectile, line_t* line);
bool P_ProjectileHitPlane(AActor* projectile, int part);

View file

@ -1271,7 +1271,7 @@ int P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams
{
maxdist = params->maxDist;
mindist = params->minDist;
fov = params->Fov;
fov = allaround ? DAngle::fromDeg(0.) : params->Fov; // [RK] Account for LOOKALLAROUND flag.
}
else
{
@ -2086,7 +2086,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx)
{
// If we find a valid target here, the wandering logic should *not*
// be activated! If would cause the seestate to be set twice.
if (P_LookForPlayers(self, true, &params))
if (P_LookForPlayers(self, (self->flags4 & MF4_LOOKALLAROUND), &params)) // [RK] Passing true for allround should only occur if the flag is actually set.
goto seeyou;
}
@ -2899,13 +2899,8 @@ void A_Chase(AActor *self)
A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0);
}
DEFINE_ACTION_FUNCTION(AActor, A_Chase)
void A_ChaseNative(AActor * self, int meleelabel, int missilelabel, int flags)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_STATELABEL(meleelabel);
PARAM_STATELABEL(missilelabel);
PARAM_INT(flags);
FName meleename = ENamedName(meleelabel - 0x10000000);
FName missilename = ENamedName(missilelabel - 0x10000000);
if (meleename != NAME__a_chase_default || missilename != NAME__a_chase_default)
@ -2913,7 +2908,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Chase)
FState *melee = StateLabels.GetState(meleelabel, self->GetClass());
FState *missile = StateLabels.GetState(missilelabel, self->GetClass());
if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false))
return 0;
return;
A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE),
!!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE), flags & 0x3fffffff);
@ -2922,6 +2917,36 @@ DEFINE_ACTION_FUNCTION(AActor, A_Chase)
{
A_DoChase(self, false, self->MeleeState, self->MissileState, true, gameinfo.nightmarefast, false, 0);
}
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_Chase, A_ChaseNative)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_STATELABEL(meleelabel);
PARAM_STATELABEL(missilelabel);
PARAM_INT(flags);
A_ChaseNative(self, meleelabel, missilelabel, flags);
return 0;
}
void A_DoChaseNative(AActor * self, FState *melee, FState *missile, int flags)
{
if ((flags & CHF_RESURRECT) && P_CheckForResurrection(self, false))
return;
A_DoChase(self, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE), !!(flags&CHF_NIGHTMAREFAST), !!(flags&CHF_DONTMOVE), flags & 0x3fffffff);
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_DoChase, A_DoChaseNative)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_STATE(melee);
PARAM_STATE(missile);
PARAM_INT(flags);
A_DoChaseNative(self, melee, missile, flags);
return 0;
}

View file

@ -410,9 +410,9 @@ enum
RADF_NOALLIES = 128,
RADF_CIRCULAR = 256
};
int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg, bool circular);
int P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance,
FName damageType, int flags, int fulldamagedistance=0, FName species = NAME_None);
int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, double distance, double fulldmgdistance, bool oldradiusdmg, bool circular);
int P_RadiusAttack (AActor *spot, AActor *source, int damage, double distance,
FName damageType, int flags, double fulldamagedistance=0.0, FName species = NAME_None);
void P_DelSeclist(msecnode_t *, msecnode_t *sector_t::*seclisthead);
void P_DelSeclist(portnode_t *, portnode_t *FLinePortal::*seclisthead);

View file

@ -5949,7 +5949,7 @@ CUSTOM_CVAR(Float, splashfactor, 1.f, CVAR_SERVERINFO)
// Used by anything without OLDRADIUSDMG flag
//==========================================================================
static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, int bombdistance, int fulldamagedistance, bool thingbombsource, bool round)
static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, double bombdistance, double fulldamagedistance, bool thingbombsource, bool round)
{
// [RH] New code. The bounding box only covers the
// height of the thing and not the height of the map.
@ -5958,7 +5958,7 @@ static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing,
double dx, dy;
double boxradius;
double bombdistancefloat = 1. / (double)(bombdistance - fulldamagedistance);
double bombdistancefloat = 1.0 / (bombdistance - fulldamagedistance);
double bombdamagefloat = (double)bombdamage;
if (!round)
@ -6005,8 +6005,8 @@ static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing,
{
len = bombspot->Distance3D (thing);
}
len = clamp<double>(len - (double)fulldamagedistance, 0, len);
points = bombdamagefloat * (1. - len * bombdistancefloat);
len = clamp<double>(len - fulldamagedistance, 0.0, len);
points = bombdamagefloat * (1.0 - len * bombdistancefloat);
// Calculate the splash and radius damage factor if called by P_RadiusAttack.
// Otherwise, just get the raw damage. This allows modders to manipulate it
@ -6034,7 +6034,7 @@ static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing,
// based on XY distance.
//==========================================================================
static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, int bombdistance, int fulldamagedistance)
static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, double bombdistance, double fulldamagedistance)
{
const int ret = fromaction ? 0 : -1; // -1 is specifically for P_RadiusAttack; continue onto another actor.
double dx, dy, dist;
@ -6055,8 +6055,8 @@ static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing,
// When called from the action function, ignore the sight check.
if (fromaction || P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))
{
dist = clamp<double>(dist - fulldamagedistance, 0, dist);
int damage = Scale(bombdamage, bombdistance - int(dist), bombdistance);
dist = clamp<double>(dist - fulldamagedistance, 0.0, dist);
int damage = (int)Scale((double)bombdamage, bombdistance - dist, bombdistance);
if (!fromaction)
{
@ -6078,7 +6078,7 @@ static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing,
// damage and not taking into account any damage reduction.
//==========================================================================
int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg, bool circular)
int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, double distance, double fulldmgdistance, bool oldradiusdmg, bool circular)
{
if (!thing)
@ -6090,10 +6090,10 @@ int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int
return damage;
}
fulldmgdistance = clamp<int>(fulldmgdistance, 0, distance - 1);
fulldmgdistance = clamp<double>(fulldmgdistance, 0.0, distance - 1.0);
// Mirroring A_Explode's behavior.
if (distance <= 0)
if (distance <= 0.0)
distance = damage;
const int newdam = oldradiusdmg
@ -6110,15 +6110,15 @@ int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int
//
//==========================================================================
int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bombdistance, FName bombmod,
int flags, int fulldamagedistance, FName species)
int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, double bombdistance, FName bombmod,
int flags, double fulldamagedistance, FName species)
{
if (bombdistance <= 0)
if (bombdistance <= 0.0)
return 0;
fulldamagedistance = clamp<int>(fulldamagedistance, 0, bombdistance - 1);
fulldamagedistance = clamp<double>(fulldamagedistance, 0.0, bombdistance - 1.0);
FPortalGroupArray grouplist(FPortalGroupArray::PGA_Full3d);
FMultiBlockThingsIterator it(grouplist, bombspot->Level, bombspot->X(), bombspot->Y(), bombspot->Z() - bombdistance, bombspot->Height + bombdistance*2, bombdistance, false, bombspot->Sector);
FMultiBlockThingsIterator it(grouplist, bombspot->Level, bombspot->X(), bombspot->Y(), bombspot->Z() - bombdistance, bombspot->Height + bombdistance*2.0, bombdistance, false, bombspot->Sector);
FMultiBlockThingsIterator::CheckResult cres;
if (flags & RADF_SOURCEISSPOT)

View file

@ -101,6 +101,7 @@
#include "fragglescript/t_fs.h"
#include "shadowinlines.h"
#include "d_net.h"
#include "model.h"
// MACROS ------------------------------------------------------------------
@ -1387,18 +1388,57 @@ bool AActor::Massacre ()
//
//----------------------------------------------------------------------------
void SerializeModelID(FSerializer &arc, const char *key, int &id)
{ // TODO: make it a proper serializable type (FModelID) instead of an int
if(arc.isWriting())
{
if(id >= 0)
{
arc(key, Models[id]->mFilePath);
}
}
else
{
if(arc.HasKey(key))
{
std::pair<FString, FString> modelFile;
arc(key, modelFile);
id = FindModel(modelFile.first.GetChars(), modelFile.second.GetChars(), true);
}
else
{
id = -1;
}
}
}
FSerializer &Serialize(FSerializer &arc, const char *key, ModelOverride &mo, ModelOverride *def)
{
arc.BeginObject(key);
arc("modelID", mo.modelID);
SerializeModelID(arc, "model", mo.modelID);
arc("surfaceSkinIDs", mo.surfaceSkinIDs);
arc.EndObject();
return arc;
}
FSerializer &Serialize(FSerializer &arc, const char *key, AnimModelOverride &amo, AnimModelOverride *def)
{
int ok = arc.BeginObject(key);
if(arc.isReading() && !ok)
{
amo.id = -1;
}
else if(ok)
{
SerializeModelID(arc, "model", amo.id);
arc.EndObject();
}
return arc;
}
FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def)
{
//TODO
arc.BeginObject(key);
arc("firstFrame", ao.firstFrame);
arc("lastFrame", ao.lastFrame);
@ -5208,15 +5248,14 @@ extern bool demonew;
//==========================================================================
//
// This function is dangerous and only designed for swapping player pawns
// This function is only designed for swapping player pawns
// over to their new ones upon changing levels or respawning. It SHOULD NOT be
// used for anything else! Do not export this functionality as it's
// meant strictly for internal usage. Only swap pointers if the thing being swapped
// to is a type of the thing being swapped from.
// meant strictly for internal usage.
//
//==========================================================================
void PlayerPointerSubstitution(AActor* oldPlayer, AActor* newPlayer)
void PlayerPointerSubstitution(AActor* oldPlayer, AActor* newPlayer, bool removeOld)
{
if (oldPlayer == nullptr || newPlayer == nullptr || oldPlayer == newPlayer
|| !oldPlayer->IsKindOf(NAME_PlayerPawn) || !newPlayer->IsKindOf(NAME_PlayerPawn))
@ -5253,20 +5292,16 @@ void PlayerPointerSubstitution(AActor* oldPlayer, AActor* newPlayer)
sec.SoundTarget = newPlayer;
}
// Update all the remaining object pointers. This is dangerous but needed to ensure
// everything functions correctly when respawning or changing levels.
// Update all the remaining object pointers.
for (DObject* probe = GC::Root; probe != nullptr; probe = probe->ObjNext)
probe->PointerSubstitution(oldPlayer, newPlayer);
probe->PointerSubstitution(oldPlayer, newPlayer, removeOld);
}
//==========================================================================
//
// This function is much safer than PlayerPointerSubstition as it only truly
// swaps a few safe pointers. This has some extra barriers to it to allow
// This has some extra barriers compared to PlayerPointerSubstitution to allow
// Actors to freely morph into other Actors which is its main usage.
// Previously this used raw pointer substitutions but that's far too
// volatile to use with modder-provided information. It also allows morphing
// to be more extendable from ZScript.
// It also allows morphing to be more extendable from ZScript.
//
//==========================================================================
@ -5311,30 +5346,6 @@ int MorphPointerSubstitution(AActor* from, AActor* to)
VMCall(func, params, 2, nullptr, 0);
}
// Only change some gameplay-related pointers that we know we can safely swap to whatever
// new Actor class is present.
AActor* mo = nullptr;
auto it = from->Level->GetThinkerIterator<AActor>();
while ((mo = it.Next()) != nullptr)
{
if (mo->target == from)
mo->target = to;
if (mo->tracer == from)
mo->tracer = to;
if (mo->master == from)
mo->master = to;
if (mo->goal == from)
mo->goal = to;
if (mo->lastenemy == from)
mo->lastenemy = to;
if (mo->LastHeard == from)
mo->LastHeard = to;
if (mo->LastLookActor == from)
mo->LastLookActor = to;
if (mo->Poisoner == from)
mo->Poisoner = to;
}
// Go through player infos.
for (int i = 0; i < MAXPLAYERS; ++i)
{
@ -5364,6 +5375,10 @@ int MorphPointerSubstitution(AActor* from, AActor* to)
sec.SoundTarget = to;
}
// Replace any object pointers that are safe to swap around.
for (DObject* probe = GC::Root; probe != nullptr; probe = probe->ObjNext)
probe->PointerSubstitution(from, to, false);
// Remaining maintenance related to morphing.
if (from->player != nullptr)
{
@ -5493,6 +5508,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag
p->mo = mobj;
mobj->player = p;
state = p->playerstate;
const auto heldWeap = state == PST_REBORN && (dmflags3 & DF3_REMEMBER_LAST_WEAP) ? p->ReadyWeapon : nullptr;
if (state == PST_REBORN || state == PST_ENTER)
{
PlayerReborn (playernum);
@ -5593,7 +5609,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag
{ // Special inventory handling for respawning in coop
IFVM(PlayerPawn, FilterCoopRespawnInventory)
{
VMValue params[] = { p->mo, oldactor };
VMValue params[] = { p->mo, oldactor, ((heldWeap == nullptr || (heldWeap->ObjectFlags & OF_EuthanizeMe)) ? nullptr : heldWeap) };
VMCall(func, params, 2, nullptr, 0);
}
}
@ -5656,7 +5672,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag
if (sec.SoundTarget == oldactor) sec.SoundTarget = nullptr;
}
PlayerPointerSubstitution (oldactor, p->mo);
PlayerPointerSubstitution (oldactor, p->mo, false);
localEventManager->PlayerRespawned(PlayerNum(p));
Behaviors.StartTypedScripts (SCRIPT_Respawn, p->mo, true);

View file

@ -164,7 +164,7 @@ void P_TerminateScript (FLevelLocals *Level, int script, const char *map);
//
// [RH] p_quake.c
//
bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double intensityX, double intensityY, double intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags, double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage);
bool P_StartQuake(FLevelLocals *Level, AActor *activator, int tid, double intensity, int duration, int damrad, int tremrad, FSoundID quakesfx);
bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double intensityX, double intensityY, double intensityZ, int duration, double damrad, double tremrad, FSoundID quakesfx, int flags, double waveSpeedX, double waveSpeedY, double waveSpeedZ, double falloff, int highpoint, double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage);
bool P_StartQuake(FLevelLocals *Level, AActor *activator, int tid, double intensity, int duration, double damrad, double tremrad, FSoundID quakesfx);
#endif

View file

@ -1278,6 +1278,7 @@ void P_PlayerThink (player_t *player)
player->cheats &= ~CF_INTERPVIEWANGLES;
player->cheats &= ~CF_SCALEDNOLERP;
player->cheats &= ~CF_NOFOVINTERP;
player->cheats &= ~CF_NOVIEWPOSINTERP;
player->mo->FloatVar("prevBob") = player->bob;
IFVIRTUALPTRNAME(player->mo, NAME_PlayerPawn, PlayerThink)

View file

@ -278,12 +278,19 @@ double getCurrentFrame(const AnimOverride &anim, double tic)
{
if(anim.framerate <= 0) return anim.startFrame;
double duration = double(anim.lastFrame - anim.firstFrame) / double(anim.framerate); // duration in seconds
double startPos = double(anim.startFrame - anim.firstFrame) / double(anim.framerate);
double frame = ((tic - anim.startTic) / GameTicRate) * anim.framerate; // position in frames
double pos = startPos + ((tic - anim.startTic) / GameTicRate); // position in seconds
double duration = double(anim.lastFrame) - anim.startFrame;
return (((anim.flags & ANIMOVERRIDE_LOOP) ? fmod(pos, duration) : min(pos, duration)) * anim.framerate) + anim.firstFrame;
if((anim.flags & ANIMOVERRIDE_LOOP) && frame >= duration)
{
frame = frame - duration;
return fmod(frame, anim.lastFrame - anim.loopFrame) + anim.loopFrame;
}
else
{
return min(frame, duration) + anim.startFrame;
}
}
static void calcFrame(const AnimOverride &anim, double tic, double &inter, int &prev, int &next)
@ -294,22 +301,7 @@ static void calcFrame(const AnimOverride &anim, double tic, double &inter, int &
inter = frame - prev;
if(frame > anim.lastFrame)
{
if(anim.flags & ANIMOVERRIDE_LOOP)
{
next = anim.loopFrame + (prev - anim.lastFrame);
}
else
{
inter = 0;
prev = next = anim.lastFrame;
}
}
else
{
next = int(ceil(frame));
}
next = int(ceil(frame));
}
void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, FTranslationID translation, AActor* actor)
@ -523,7 +515,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
skinid = smf->skinIDs[i];
}
if (modelid >= 0)
if (modelid >= 0 && modelid < Models.size())
{
FModel * mdl = Models[modelid];
auto tex = skinid.isValid() ? TexMan.GetGameTexture(skinid, true) : nullptr;

View file

@ -2367,6 +2367,7 @@ void HWWall::ProcessLowerMiniseg(HWWallDispatcher *di, FRenderState& state, seg_
this->frontsector = frontsector;
this->backsector = backsector;
this->sub = NULL;
//this->lightmap = nullptr; // this came from gzdoom commit f796e55c0d313e1c48c3472a7334de37cc4ae775
vertex_t * v1 = seg->v1;
vertex_t * v2 = seg->v2;

View file

@ -78,7 +78,7 @@ struct InterpolationViewer
{
struct instance
{
DVector3 Pos;
DVector3 Pos, ViewPos;
DRotator Angles;
DRotator ViewAngles;
};
@ -605,6 +605,22 @@ void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player
// Now that the base position and angles are set, add offsets.
const DViewPosition* const vPos = iView->ViewActor->ViewPos;
if (vPos != nullptr && !(vPos->Flags & VPSF_ABSOLUTEPOS)
&& (player == nullptr || gamestate == GS_TITLELEVEL || (!(player->cheats & CF_CHASECAM) && (!r_deathcamera || !(iView->ViewActor->flags6 & MF6_KILLED)))))
{
DVector3 vOfs = {};
if (player == nullptr || !(player->cheats & CF_NOVIEWPOSINTERP))
vOfs = iView->Old.ViewPos * inverseTicFrac + iView->New.ViewPos * ticFrac;
else
vOfs = iView->New.ViewPos;
if (vPos->Flags & VPSF_ABSOLUTEOFFSET)
iView->ViewOffset += vOfs;
else
iView->RelativeViewOffset += vOfs;
}
DVector3 posOfs = iView->ViewOffset;
if (!iView->RelativeViewOffset.isZero())
posOfs += DQuaternion::FromAngles(viewPoint.Angles.Yaw, viewPoint.Angles.Pitch, viewPoint.Angles.Roll) * iView->RelativeViewOffset;
@ -916,8 +932,8 @@ void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AA
viewPoint.showviewer = false;
viewPoint.bForceNoViewer = matchPlayer;
if (gamestate != GS_TITLELEVEL &&
((player != nullptr && (player->cheats & CF_CHASECAM)) || (r_deathcamera && (viewPoint.camera->flags6 & MF6_KILLED))))
if (player != nullptr && gamestate != GS_TITLELEVEL
&& ((player->cheats & CF_CHASECAM) || (r_deathcamera && (viewPoint.camera->flags6 & MF6_KILLED))))
{
// The cam Actor should probably be visible in third person.
viewPoint.showviewer = true;
@ -925,7 +941,8 @@ void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AA
iView->ViewOffset.Z = clamp<double>(chase_height, -1000.0, 1000.0);
iView->RelativeViewOffset.X = -clamp<double>(chase_dist, 0.0, 30000.0);
}
else if (viewOffset != nullptr)
if (viewOffset != nullptr)
{
// No chase/death cam, so use the view offset.
if (!viewPoint.bForceNoViewer)
@ -933,16 +950,13 @@ void R_SetupFrame(FRenderViewpoint& viewPoint, const FViewWindow& viewWindow, AA
if (viewOffset->Flags & VPSF_ABSOLUTEPOS)
{
iView->New.ViewPos.Zero();
if (!matchPlayer)
camPos = viewOffset->Offset;
}
else if (viewOffset->Flags & VPSF_ABSOLUTEOFFSET)
{
iView->ViewOffset += viewOffset->Offset;
}
else
{
iView->RelativeViewOffset = viewOffset->Offset;
iView->New.ViewPos = viewOffset->Offset;
}
}

View file

@ -1317,14 +1317,14 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetRadiusDamage, P_GetRadiusDamage)
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(thing, AActor);
PARAM_INT(damage);
PARAM_INT(distance);
PARAM_INT(fulldmgdistance);
PARAM_FLOAT(distance);
PARAM_FLOAT(fulldmgdistance);
PARAM_BOOL(oldradiusdmg);
PARAM_BOOL(circular);
ACTION_RETURN_INT(P_GetRadiusDamage(self, thing, damage, distance, fulldmgdistance, oldradiusdmg, circular));
}
static int RadiusAttack(AActor *self, AActor *bombsource, int bombdamage, int bombdistance, int damagetype, int flags, int fulldamagedistance, int species)
static int RadiusAttack(AActor *self, AActor *bombsource, int bombdamage, double bombdistance, int damagetype, int flags, double fulldamagedistance, int species)
{
return P_RadiusAttack(self, bombsource, bombdamage, bombdistance, ENamedName(damagetype), flags, fulldamagedistance, ENamedName(species));
}
@ -1334,10 +1334,10 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, RadiusAttack, RadiusAttack)
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(bombsource, AActor);
PARAM_INT(bombdamage);
PARAM_INT(bombdistance);
PARAM_FLOAT(bombdistance);
PARAM_INT(damagetype);
PARAM_INT(flags);
PARAM_INT(fulldamagedistance);
PARAM_FLOAT(fulldamagedistance);
PARAM_INT(species);
ACTION_RETURN_INT(RadiusAttack(self, bombsource, bombdamage, bombdistance, damagetype, flags, fulldamagedistance, species));
}

View file

@ -1833,6 +1833,7 @@ OptionMenu CoopOptions protected
Option "$GMPLYMNU_SHAREKEYS", "sv_coopsharekeys", "YesNo"
Option "$GMPLYMNU_LOCALITEMS", "sv_localitems", "YesNo"
Option "$GMPLYMNU_NOLOCALDROP", "sv_nolocaldrops", "YesNo"
Option "$GMPLYMNU_REMEMBERWEAP", "sv_rememberlastweapon", "YesNo"
Class "GameplayMenu"
}

View file

@ -273,7 +273,7 @@ class Actor : Thinker native
meta Name BloodType2; // Bloopsplatter replacement type
meta Name BloodType3; // AxeBlood replacement type
meta bool DontHurtShooter;
meta int ExplosionRadius;
meta double ExplosionRadius;
meta int ExplosionDamage;
meta int MeleeDamage;
meta Sound MeleeSound;
@ -432,7 +432,7 @@ class Actor : Thinker native
DefThreshold 100;
BloodType "Blood", "BloodSplatter", "AxeBlood";
ExplosionDamage 128;
ExplosionRadius -1; // i.e. use ExplosionDamage value
ExplosionRadius -1.0; // i.e. use ExplosionDamage value
MissileHeight 32;
SpriteAngle 0;
SpriteRotation 0;
@ -1145,6 +1145,7 @@ class Actor : Thinker native
void A_Fall() { A_NoBlocking(); }
native void A_Look();
native void A_Chase(statelabel melee = '_a_chase_default', statelabel missile = '_a_chase_default', int flags = 0);
native void A_DoChase(State melee, State missile, int flags = 0);
native void A_VileChase();
native bool A_CheckForResurrection(State state = null, Sound snd = 0);
native void A_BossDeath();
@ -1225,9 +1226,9 @@ class Actor : Thinker native
native void A_CustomMeleeAttack(int damage = 0, sound meleesound = "", sound misssound = "", name damagetype = "none", bool bleed = true);
native void A_CustomComboAttack(class<Actor> missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true);
native void A_Burst(class<Actor> chunktype);
native void A_RadiusDamageSelf(int damage = 128, double distance = 128, int flags = 0, class<Actor> flashtype = null);
native int GetRadiusDamage(Actor thing, int damage, int distance, int fulldmgdistance = 0, bool oldradiusdmg = false, bool circular = false);
native int RadiusAttack(Actor bombsource, int bombdamage, int bombdistance, Name bombmod = 'none', int flags = RADF_HURTSOURCE, int fulldamagedistance = 0, name species = "None");
native void A_RadiusDamageSelf(int damage = 128, double distance = 128.0, int flags = 0, class<Actor> flashtype = null);
native int GetRadiusDamage(Actor thing, int damage, double distance, double fulldmgdistance = 0.0, bool oldradiusdmg = false, bool circular = false);
native int RadiusAttack(Actor bombsource, int bombdamage, double bombdistance, Name bombmod = 'none', int flags = RADF_HURTSOURCE, double fulldamagedistance = 0.0, name species = "None");
native void A_Respawn(int flags = 1);
native void A_RestoreSpecialPosition();
@ -1247,8 +1248,8 @@ class Actor : Thinker native
deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserArray(name varname, int index, int value);
deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserVarFloat(name varname, double value);
deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserArrayFloat(name varname, int index, double value);
native void A_Quake(double intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake");
native void A_QuakeEx(double intensityX, double intensityY, double intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, int falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0, double damageMultiplier = 1, double thrustMultiplier = 0.5, int damage = 0);
native void A_Quake(double intensity, int duration, double damrad, double tremrad, sound sfx = "world/quake");
native void A_QuakeEx(double intensityX, double intensityY, double intensityZ, int duration, double damrad, double tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, double falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0, double damageMultiplier = 1, double thrustMultiplier = 0.5, int damage = 0);
action native void A_SetTics(int tics);
native void A_DamageSelf(int amount, name damagetype = "none", int flags = 0, class<Actor> filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT);
native void A_DamageTarget(int amount, name damagetype = "none", int flags = 0, class<Actor> filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT);
@ -1304,8 +1305,8 @@ class Actor : Thinker native
native bool A_AttachLight(Name lightid, int type, Color lightcolor, int radius1, int radius2, int flags = 0, Vector3 ofs = (0,0,0), double param = 0, double spoti = 10, double spoto = 25, double spotp = 0);
native bool A_RemoveLight(Name lightid);
native version("4.12") void SetAnimation(Name animName, double framerate = -1, int startFrame = -1, int loopFrame= -1, int interpolateTics = -1, int flags = 0);
native version("4.12") ui void SetAnimationUI(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int interpolateTics = -1, int flags = 0);
native version("4.12") void SetAnimation(Name animName, double framerate = -1, int startFrame = -1, int loopFrame= -1, int endFrame = -1, int interpolateTics = -1, int flags = 0);
native version("4.12") ui void SetAnimationUI(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int endFrame = -1, int interpolateTics = -1, int flags = 0);
native version("4.12") void SetAnimationFrameRate(double framerate);
native version("4.12") ui void SetAnimationFrameRateUI(double framerate);

View file

@ -569,7 +569,7 @@ extend class Actor
//
//==========================================================================
int A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class<Actor> pufftype = "BulletPuff", name damagetype = "none")
int A_Explode(int damage = -1, double distance = -1.0, int flags = XF_HURTSOURCE, bool alert = false, double fulldamagedistance = 0.0, int nails = 0, int naildamage = 10, class<Actor> pufftype = "BulletPuff", name damagetype = "none")
{
if (damage < 0) // get parameters from metadata
@ -626,7 +626,7 @@ extend class Actor
}
deprecated("2.3", "For Dehacked use only")
void A_RadiusDamage(int dam, int dist)
void A_RadiusDamage(int dam, double dist)
{
A_Explode(dam, dist);
}
@ -637,10 +637,10 @@ extend class Actor
//
//==========================================================================
void A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0, name species = "None")
void A_RadiusThrust(int force = 128, double distance = -1.0, int flags = RTF_AFFECTSOURCE, double fullthrustdistance = 0.0, name species = "None")
{
if (force == 0) force = 128;
if (distance <= 0) distance = abs(force);
if (distance <= 0.0) distance = abs(force);
bool nothrust = false;
if (target)

View file

@ -12,6 +12,7 @@ class Inventory : Actor
private bool bSharingItem; // Currently being shared (avoid infinite recursions).
private bool pickedUp[MAXPLAYERS]; // If items are set to local, track who already picked it up.
private bool bCreatingCopy; // Tells GoAway that it needs to return true so a new copy of the item is spawned.
deprecated("3.7") private int ItemFlags;
Actor Owner; // Who owns this item? NULL if it's still a pickup.
@ -835,9 +836,11 @@ class Inventory : Actor
Inventory give = self;
if (localPickUp)
{
give = Inventory(Spawn(GetClass()));
give = CreateLocalCopy(toucher);
if (!give)
return;
localPickUp = give != self;
}
bool res;
@ -1043,6 +1046,9 @@ class Inventory : Actor
protected bool GoAway ()
{
if (bCreatingCopy)
return true;
// Dropped items never stick around
if (bDropped)
{
@ -1113,6 +1119,17 @@ class Inventory : Actor
pickedUp[pNum] = true;
DisableLocalRendering(pNum, true);
}
// Force spawn a new version of the item. This needs to use CreateCopy so that
// any transferrable properties on the item get correctly set.
Inventory CreateLocalCopy(Actor client)
{
bCreatingCopy = true;
let item = CreateCopy(client);
bCreatingCopy = false;
return item;
}
//===========================================================================
//

View file

@ -867,7 +867,7 @@ class PlayerPawn : Actor
//
//===========================================================================
void FilterCoopRespawnInventory (PlayerPawn oldplayer)
void FilterCoopRespawnInventory (PlayerPawn oldplayer, Weapon curHeldWeapon = null)
{
// If we're losing everything, this is really simple.
if (sv_cooploseinventory)
@ -876,6 +876,10 @@ class PlayerPawn : Actor
return;
}
// Make sure to get the real held weapon before messing with the inventory.
if (curHeldWeapon && curHeldWeapon.bPowered_Up)
curHeldWeapon = curHeldWeapon.SisterWeapon;
// Walk through the old player's inventory and destroy or modify
// according to dmflags.
Inventory next;
@ -957,7 +961,15 @@ class PlayerPawn : Actor
ObtainInventory (oldplayer);
player.ReadyWeapon = NULL;
PickNewWeapon (NULL);
if (curHeldWeapon && curHeldWeapon.owner == self && curHeldWeapon.CheckAmmo(Weapon.EitherFire, false))
{
player.PendingWeapon = curHeldWeapon;
BringUpWeapon();
}
else
{
PickNewWeapon (NULL);
}
}
@ -1251,6 +1263,12 @@ class PlayerPawn : Actor
return forward, side;
}
virtual void ApplyAirControl(out double movefactor, out double bobfactor)
{
movefactor *= level.aircontrol;
bobfactor *= level.aircontrol;
}
//----------------------------------------------------------------------------
//
// PROC P_MovePlayer
@ -1294,8 +1312,8 @@ class PlayerPawn : Actor
if (!player.onground && !bNoGravity && !waterlevel)
{
// [RH] allow very limited movement if not on ground.
movefactor *= level.aircontrol;
bobfactor*= level.aircontrol;
// [AA] but also allow authors to override it.
ApplyAirControl(movefactor, bobfactor);
}
fm = cmd.forwardmove;

View file

@ -375,6 +375,7 @@ enum ESetAnimationFlags
{
SAF_INSTANT = 1 << 0,
SAF_LOOP = 1 << 1,
SAF_NOOVERRIDE = 1 << 2,
};
// Change model flags
@ -1161,6 +1162,7 @@ enum EPlayerCheats
CF_INTERPVIEWANGLES = 1 << 15, // [MR] flag for interpolating view angles without interpolating the entire frame
CF_NOFOVINTERP = 1 << 16, // [B] Disable FOV interpolation when instantly zooming
CF_SCALEDNOLERP = 1 << 17, // [MR] flag for applying angles changes in the ticrate without interpolating the frame
CF_NOVIEWPOSINTERP = 1 << 18, // Disable view position interpolation.
CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths.

View file

@ -28,7 +28,7 @@ struct Destructible native play
static native void DamageLinedef(Line def, Actor source, int damage, Name damagetype, int side, vector3 position, bool isradius);
static native void GeometryLineAttack(TraceResults trace, Actor thing, int damage, Name damagetype);
static native void GeometryRadiusAttack(Actor bombspot, Actor bombsource, int bombdamage, int bombdistance, Name damagetype, int fulldamagedistance);
static native void GeometryRadiusAttack(Actor bombspot, Actor bombsource, int bombdamage, double bombdistance, Name damagetype, double fulldamagedistance);
static native bool ProjectileHitLinedef(Actor projectile, Line def);
static native bool ProjectileHitPlane(Actor projectile, SectorPart part);