mirror of
https://github.com/DrBeef/QuestZDoom.git
synced 2025-03-04 08:31:49 +00:00
Update to LZDoom 3.86
This commit is contained in:
parent
9d6e140f7c
commit
fede580be9
133 changed files with 2364 additions and 1364 deletions
|
@ -18,6 +18,7 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<application android:allowBackup="false" android:icon="@drawable/ic_qquest" android:label="@string/qzdoom">
|
||||
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
|
||||
<meta-data android:name="com.oculus.supportedDevices" android:value="quest|delmar"/>
|
||||
<!-- The activity is the built-in NativeActivity framework class. -->
|
||||
<!-- launchMode is set to singleTask because there should never be multiple copies of the app running. -->
|
||||
<!-- Theme.Black.NoTitleBar.Fullscreen gives solid black instead of a (bad stereoscopic) gradient on app transition. -->
|
||||
|
@ -29,8 +30,9 @@
|
|||
android:label="@string/qzdoom"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="landscape"
|
||||
android:resizeableActivity="false"
|
||||
android:excludeFromRecents="false"
|
||||
android:configChanges="screenSize|screenLayout|orientation|keyboardHidden|keyboard|navigation|uiMode">
|
||||
android:configChanges="density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode">
|
||||
<!-- Tell NativeActivity the name of the .so -->
|
||||
<meta-data android:name="android.app.lib_name" android:value="QuestZDoom" />
|
||||
<!-- This filter lets the apk show up as a launchable icon. -->
|
||||
|
|
|
@ -270,7 +270,8 @@ void Instruments::init_sf(SFInsts *rec)
|
|||
return;
|
||||
}
|
||||
|
||||
if(load_soundfont(&sfinfo, rec->tf))
|
||||
// SoundFont spec, 7.2: ... contains a minimum of two records, one record for each preset and one for a terminal record
|
||||
if(load_soundfont(&sfinfo, rec->tf) || sfinfo.npresets < 2)
|
||||
{
|
||||
end_soundfont(rec);
|
||||
return;
|
||||
|
@ -278,7 +279,7 @@ void Instruments::init_sf(SFInsts *rec)
|
|||
|
||||
correct_samples(&sfinfo);
|
||||
current_sfrec = rec;
|
||||
for (i = 0; i < sfinfo.npresets; i++) {
|
||||
for (i = 0; i < sfinfo.npresets - 1; i++) {
|
||||
int bank = sfinfo.preset[i].bank;
|
||||
int preset = sfinfo.preset[i].preset;
|
||||
|
||||
|
|
|
@ -850,7 +850,7 @@ public:
|
|||
return (Pos().XY() - otherpos).LengthSquared();
|
||||
}
|
||||
|
||||
double Distance2D(AActor *other, bool absolute = false)
|
||||
double Distance2D(AActor *other, bool absolute = false) const
|
||||
{
|
||||
DVector2 otherpos = absolute ? other->Pos() : other->PosRelative(this);
|
||||
return (Pos().XY() - otherpos).Length();
|
||||
|
@ -861,7 +861,7 @@ public:
|
|||
return DVector2(X() - x, Y() - y).Length();
|
||||
}
|
||||
|
||||
double Distance2D(AActor *other, double xadd, double yadd, bool absolute = false)
|
||||
double Distance2D(AActor *other, double xadd, double yadd, bool absolute = false) const
|
||||
{
|
||||
DVector3 otherpos = absolute ? other->Pos() : other->PosRelative(this);
|
||||
return DVector2(X() - otherpos.X + xadd, Y() - otherpos.Y + yadd).Length();
|
||||
|
@ -1490,7 +1490,7 @@ public:
|
|||
|
||||
// This is used by many vertical velocity calculations.
|
||||
// Better have it in one place, if something needs to be changed about the formula.
|
||||
double DistanceBySpeed(AActor *dest, double speed)
|
||||
double DistanceBySpeed(AActor *dest, double speed) const
|
||||
{
|
||||
return MAX(1., Distance2D(dest) / speed);
|
||||
}
|
||||
|
@ -1500,7 +1500,7 @@ public:
|
|||
void DeleteAttachedLights();
|
||||
static void DeleteAllAttachedLights();
|
||||
static void RecreateAllAttachedLights();
|
||||
bool isFrozen();
|
||||
bool isFrozen() const;
|
||||
|
||||
bool hasmodel;
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ inline double AActor::AttackOffset(double offset)
|
|||
|
||||
}
|
||||
|
||||
inline bool AActor::isFrozen()
|
||||
inline bool AActor::isFrozen() const
|
||||
{
|
||||
if (!(flags5 & MF5_NOTIMEFREEZE))
|
||||
{
|
||||
|
|
|
@ -2991,7 +2991,7 @@ void AM_drawThings ()
|
|||
while (t)
|
||||
{
|
||||
if (am_cheat > 0 || !(t->flags6 & MF6_NOTONAUTOMAP)
|
||||
|| (am_thingrenderstyles && !(t->renderflags & RF_INVISIBLE)))
|
||||
|| (am_thingrenderstyles && !(t->renderflags & RF_INVISIBLE) && !(t->flags6 & MF6_NOTONAUTOMAP)))
|
||||
{
|
||||
DVector3 pos = t->PosRelative(MapPortalGroup);
|
||||
p.x = pos.X;
|
||||
|
|
|
@ -686,8 +686,8 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
|
|||
}
|
||||
int pick = 0;
|
||||
|
||||
// We got more than one so present the IWAD selection box.
|
||||
if (picks.Size() > 1)
|
||||
// Present the IWAD selection box.
|
||||
if (picks.Size() > 0 && !iwadparm)
|
||||
{
|
||||
// Locate the user's prefered IWAD, if it was found.
|
||||
if (defaultiwad[0] != '\0')
|
||||
|
@ -702,7 +702,7 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (picks.Size() > 1)
|
||||
if (picks.Size() > 0)
|
||||
{
|
||||
if (!havepicked)
|
||||
{
|
||||
|
|
|
@ -620,6 +620,12 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
|
|||
w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE2;
|
||||
break;
|
||||
|
||||
case 7: // Stricter MBF compatibility
|
||||
v = COMPATF_CORPSEGIBS | COMPATF_NOBLOCKFRIENDS | COMPATF_MBFMONSTERMOVE | COMPATF_INVISIBILITY |
|
||||
COMPATF_NOTOSSDROPS | COMPATF_MUSHROOM | COMPATF_NO_PASSMOBJ | COMPATF_BOOMSCROLL | COMPATF_WALLRUN |
|
||||
COMPATF_TRACE | COMPATF_HITSCAN | COMPATF_MISSILECLIP | COMPATF_MASKEDMIDTEX | COMPATF_SOUNDTARGET;
|
||||
w = COMPATF2_POINTONLINE | COMPATF2_EXPLODE1 | COMPATF2_EXPLODE2;
|
||||
break;
|
||||
}
|
||||
compatflags = v;
|
||||
compatflags2 = w;
|
||||
|
@ -3016,25 +3022,6 @@ void FStartupScreen::AppendStatusLine(const char *status)
|
|||
{
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// DeleteStartupScreen
|
||||
//
|
||||
// Makes sure the startup screen has been deleted before quitting.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void DeleteStartupScreen()
|
||||
{
|
||||
if (StartScreen != nullptr)
|
||||
{
|
||||
delete StartScreen;
|
||||
StartScreen = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FStartupScreen::Progress(void) {}
|
||||
void FStartupScreen::NetInit(char const *,int) {}
|
||||
void FStartupScreen::NetProgress(int) {}
|
||||
|
|
|
@ -73,6 +73,7 @@ CVAR (Bool, neverswitchonpickup, false, CVAR_USERINFO | CVAR_ARCHIVE);
|
|||
CVAR (Float, movebob, 0.25f, CVAR_USERINFO | CVAR_ARCHIVE);
|
||||
CVAR (Float, stillbob, 0.f, CVAR_USERINFO | CVAR_ARCHIVE);
|
||||
CVAR (Float, wbobspeed, 1.f, CVAR_USERINFO | CVAR_ARCHIVE);
|
||||
CVAR (Float, wbobfire, 0.f, CVAR_USERINFO | CVAR_ARCHIVE);
|
||||
CVAR (String, playerclass, "Fighter", CVAR_USERINFO | CVAR_ARCHIVE);
|
||||
CVAR (Bool, classicflight, false, CVAR_USERINFO | CVAR_ARCHIVE);
|
||||
|
||||
|
@ -88,6 +89,7 @@ enum
|
|||
INFO_MoveBob,
|
||||
INFO_StillBob,
|
||||
INFO_WBobSpeed,
|
||||
INFO_WBobFire,
|
||||
INFO_PlayerClass,
|
||||
INFO_ColorSet,
|
||||
INFO_ClassicFlight,
|
||||
|
|
|
@ -232,6 +232,10 @@ struct userinfo_t : TMap<FName,FBaseCVar *>
|
|||
{
|
||||
return *static_cast<FFloatCVar *>(*CheckKey(NAME_WBobSpeed));
|
||||
}
|
||||
double GetWBobFire() const
|
||||
{
|
||||
return *static_cast<FFloatCVar *>(*CheckKey(NAME_WBobFire));
|
||||
}
|
||||
int GetPlayerClassNum() const
|
||||
{
|
||||
return *static_cast<FIntCVar *>(*CheckKey(NAME_PlayerClass));
|
||||
|
|
|
@ -273,6 +273,7 @@ static const char *DecalKeywords[] =
|
|||
"colors",
|
||||
"animator",
|
||||
"lowerdecal",
|
||||
"opaqueblood",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -293,7 +294,8 @@ enum
|
|||
DECAL_SHADE,
|
||||
DECAL_COLORS,
|
||||
DECAL_ANIMATOR,
|
||||
DECAL_LOWERDECAL
|
||||
DECAL_LOWERDECAL,
|
||||
DECAL_OPAQUEBLOOD,
|
||||
};
|
||||
|
||||
const FDecalTemplate *FDecalBase::GetDecal () const
|
||||
|
@ -572,6 +574,11 @@ void FDecalLib::ParseDecal (FScanner &sc)
|
|||
sc.MustGetString ();
|
||||
newdecal.LowerDecal = GetDecalByName (sc.String);
|
||||
break;
|
||||
|
||||
case DECAL_OPAQUEBLOOD:
|
||||
newdecal.RenderStyle = STYLE_Normal;
|
||||
newdecal.opaqueBlood = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
FRenderStyle RenderStyle;
|
||||
FTextureID PicNum;
|
||||
uint16_t RenderFlags;
|
||||
bool opaqueBlood;
|
||||
double Alpha; // same as actor->alpha
|
||||
const FDecalAnimator *Animator;
|
||||
const FDecalBase *LowerDecal;
|
||||
|
|
|
@ -3,20 +3,87 @@
|
|||
#include "scripting/vm/vm.h"
|
||||
#include "serializer.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// DObject implementations for Dictionary and DictionaryIterator
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
IMPLEMENT_CLASS(Dictionary, false, false);
|
||||
|
||||
IMPLEMENT_CLASS(DictionaryIterator, false, true);
|
||||
|
||||
IMPLEMENT_POINTERS_START(DictionaryIterator)
|
||||
IMPLEMENT_POINTER(Dict)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// Dictionary functions
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
void Dictionary::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize(arc);
|
||||
|
||||
constexpr char key[] { "dictionary" };
|
||||
|
||||
if (arc.isWriting())
|
||||
{
|
||||
// Pass this instance to serializer.
|
||||
Dictionary *pointerToThis = this;
|
||||
arc(key, pointerToThis);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Receive new Dictionary, copy contents, clean up.
|
||||
Dictionary *pointerToDeserializedDictionary;
|
||||
arc(key, pointerToDeserializedDictionary);
|
||||
Map.TransferFrom(pointerToDeserializedDictionary->Map);
|
||||
pointerToDeserializedDictionary->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
static Dictionary *DictCreate()
|
||||
{
|
||||
Dictionary *dict { Create<Dictionary>() };
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
static void DictInsert(Dictionary *dict, const FString &key, const FString &value)
|
||||
{
|
||||
dict->Map.Insert(key, value);
|
||||
}
|
||||
|
||||
static void DictAt(const Dictionary *dict, const FString &key, FString *result)
|
||||
{
|
||||
const FString *value = dict->Map.CheckKey(key);
|
||||
*result = value ? *value : "";
|
||||
}
|
||||
|
||||
static void DictToString(const Dictionary *dict, FString *result)
|
||||
{
|
||||
*result = DictionaryToString(*dict);
|
||||
}
|
||||
|
||||
static void DictRemove(Dictionary *dict, const FString &key)
|
||||
{
|
||||
dict->Map.Remove(key);
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// Dictionary exports
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Dictionary, Create)
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Create, DictCreate)
|
||||
{
|
||||
ACTION_RETURN_POINTER(new Dictionary);
|
||||
}
|
||||
|
||||
static void DictInsert(Dictionary *dict, const FString &key, const FString &value)
|
||||
{
|
||||
dict->Insert(key, value);
|
||||
ACTION_RETURN_POINTER(DictCreate());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Insert, DictInsert)
|
||||
|
@ -28,12 +95,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Insert, DictInsert)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void DictAt(const Dictionary *dict, const FString &key, FString *result)
|
||||
{
|
||||
const FString *value = dict->CheckKey(key);
|
||||
*result = value ? *value : "";
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, At, DictAt)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
||||
|
@ -43,11 +104,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, At, DictAt)
|
|||
ACTION_RETURN_STRING(result);
|
||||
}
|
||||
|
||||
static void DictToString(const Dictionary *dict, FString *result)
|
||||
{
|
||||
*result = DictionaryToString(*dict);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, ToString, DictToString)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(Dictionary);
|
||||
|
@ -56,21 +112,11 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, ToString, DictToString)
|
|||
ACTION_RETURN_STRING(result);
|
||||
}
|
||||
|
||||
static Dictionary *DictFromString(const FString& string)
|
||||
{
|
||||
return DictionaryFromString(string);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, FromString, DictFromString)
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, FromString, DictionaryFromString)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_STRING(string);
|
||||
ACTION_RETURN_POINTER(DictFromString(string));
|
||||
}
|
||||
|
||||
static void DictRemove(Dictionary *dict, const FString &key)
|
||||
{
|
||||
dict->Remove(key);
|
||||
ACTION_RETURN_POINTER(DictionaryFromString(string));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Remove, DictRemove)
|
||||
|
@ -83,21 +129,65 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Dictionary, Remove, DictRemove)
|
|||
|
||||
//=====================================================================================
|
||||
//
|
||||
// DictionaryIterator exports
|
||||
// DictionaryIterator functions
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
DictionaryIterator::DictionaryIterator(const Dictionary &dict)
|
||||
: Iterator(dict)
|
||||
DictionaryIterator::DictionaryIterator()
|
||||
: Iterator(nullptr)
|
||||
, Pair(nullptr)
|
||||
, Dict(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
static DictionaryIterator *DictIteratorCreate(const Dictionary *dict)
|
||||
void DictionaryIterator::Serialize(FSerializer &arc)
|
||||
{
|
||||
return new DictionaryIterator(*dict);
|
||||
if (arc.isWriting())
|
||||
{
|
||||
I_Error("Attempt to save pointer to unhandled type DictionaryIterator");
|
||||
}
|
||||
}
|
||||
|
||||
void DictionaryIterator::init(Dictionary *dict)
|
||||
{
|
||||
Iterator = std::make_unique<Dictionary::ConstIterator>(dict->Map);
|
||||
Dict = dict;
|
||||
|
||||
GC::WriteBarrier(this, Dict);
|
||||
}
|
||||
|
||||
static DictionaryIterator *DictIteratorCreate(Dictionary *dict)
|
||||
{
|
||||
DictionaryIterator *iterator = Create<DictionaryIterator>();
|
||||
iterator->init(dict);
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
static int DictIteratorNext(DictionaryIterator *self)
|
||||
{
|
||||
assert(self->Iterator != nullptr);
|
||||
|
||||
const bool hasNext { self->Iterator->NextPair(self->Pair) };
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
static void DictIteratorKey(const DictionaryIterator *self, FString *result)
|
||||
{
|
||||
*result = self->Pair ? self->Pair->Key : FString {};
|
||||
}
|
||||
|
||||
static void DictIteratorValue(const DictionaryIterator *self, FString *result)
|
||||
{
|
||||
*result = self->Pair ? self->Pair->Value : FString {};
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// DictionaryIterator exports
|
||||
//
|
||||
//=====================================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Create, DictIteratorCreate)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
|
@ -105,22 +195,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Create, DictIteratorCreate)
|
|||
ACTION_RETURN_POINTER(DictIteratorCreate(dict));
|
||||
}
|
||||
|
||||
static int DictIteratorNext(DictionaryIterator *self)
|
||||
{
|
||||
return self->Iterator.NextPair(self->Pair);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Next, DictIteratorNext)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
||||
ACTION_RETURN_BOOL(DictIteratorNext(self));
|
||||
}
|
||||
|
||||
static void DictIteratorKey(const DictionaryIterator *self, FString *result)
|
||||
{
|
||||
*result = self->Pair ? self->Pair->Key : FString {};
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Key, DictIteratorKey)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
||||
|
@ -129,11 +209,6 @@ DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Key, DictIteratorKey)
|
|||
ACTION_RETURN_STRING(result);
|
||||
}
|
||||
|
||||
static void DictIteratorValue(const DictionaryIterator *self, FString *result)
|
||||
{
|
||||
*result = self->Pair ? self->Pair->Value : FString {};
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_DictionaryIterator, Value, DictIteratorValue)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(DictionaryIterator);
|
||||
|
|
|
@ -2,13 +2,69 @@
|
|||
|
||||
#include "tarray.h"
|
||||
#include "zstring.h"
|
||||
#include "dobject.h"
|
||||
|
||||
using Dictionary = TMap<FString, FString>;
|
||||
#include <memory>
|
||||
|
||||
struct DictionaryIterator
|
||||
/**
|
||||
* @brief The Dictionary class exists to be exported to ZScript.
|
||||
*
|
||||
* It is a string-to-string map.
|
||||
*
|
||||
* It is derived from DObject to be a part of normal GC process.
|
||||
*/
|
||||
class Dictionary final : public DObject
|
||||
{
|
||||
explicit DictionaryIterator(const Dictionary &dict);
|
||||
DECLARE_CLASS(Dictionary, DObject)
|
||||
|
||||
Dictionary::ConstIterator Iterator;
|
||||
Dictionary::ConstPair *Pair;
|
||||
public:
|
||||
|
||||
using StringMap = TMap<FString, FString>;
|
||||
using ConstIterator = StringMap::ConstIterator;
|
||||
using ConstPair = StringMap::ConstPair;
|
||||
|
||||
void Serialize(FSerializer &arc) override;
|
||||
|
||||
StringMap Map;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The DictionaryIterator class exists to be exported to ZScript.
|
||||
*
|
||||
* It provides iterating over a Dictionary. The order is not specified.
|
||||
*
|
||||
* It is derived from DObject to be a part of normal GC process.
|
||||
*/
|
||||
class DictionaryIterator final : public DObject
|
||||
{
|
||||
DECLARE_CLASS(DictionaryIterator, DObject)
|
||||
HAS_OBJECT_POINTERS
|
||||
|
||||
public:
|
||||
|
||||
~DictionaryIterator() override = default;
|
||||
|
||||
/**
|
||||
* IMPLEMENT_CLASS macro needs a constructor without parameters.
|
||||
*
|
||||
* @see init().
|
||||
*/
|
||||
DictionaryIterator();
|
||||
|
||||
void Serialize(FSerializer &arc) override;
|
||||
|
||||
/**
|
||||
* @brief init function complements constructor.
|
||||
* @attention always call init after constructing DictionaryIterator.
|
||||
*/
|
||||
void init(Dictionary *dict);
|
||||
|
||||
std::unique_ptr<Dictionary::ConstIterator> Iterator;
|
||||
Dictionary::ConstPair *Pair;
|
||||
|
||||
/**
|
||||
* @brief Dictionary attribute exists for holding a pointer to iterated
|
||||
* dictionary, so it is known by GC.
|
||||
*/
|
||||
Dictionary *Dict;
|
||||
};
|
||||
|
|
|
@ -495,6 +495,13 @@ void DObject::StaticPointerSubstitution (AActor *old, AActor *notOld)
|
|||
size_t changed = 0;
|
||||
int i;
|
||||
|
||||
// This is only allowed to replace players or swap out morphed monsters
|
||||
if (!old->IsKindOf(NAME_PlayerPawn) || (notOld != nullptr && !notOld->IsKindOf(NAME_PlayerPawn)))
|
||||
{
|
||||
if (notOld == nullptr) return;
|
||||
if (!old->IsKindOf(NAME_MorphedMonster) && !notOld->IsKindOf(NAME_MorphedMonster)) return;
|
||||
}
|
||||
|
||||
// Go through all objects.
|
||||
i = 0;DObject *last=0;
|
||||
for (probe = GC::Root; probe != NULL; probe = probe->ObjNext)
|
||||
|
|
|
@ -416,6 +416,7 @@ enum EMapThingFlags
|
|||
|
||||
MTF_SECRET = 0x080000, // Secret pickup
|
||||
MTF_NOINFIGHTING = 0x100000,
|
||||
MTF_NOCOUNT = 0x200000, // Removes COUNTKILL/COUNTITEM
|
||||
|
||||
// BOOM and DOOM compatible versions of some of the above
|
||||
|
||||
|
|
|
@ -359,6 +359,14 @@ CCMD (slot)
|
|||
VMCall(func, param, 3, &ret, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// [Nash] Option to display the name of the weapon being switched to.
|
||||
if (players[consoleplayer].playerstate != PST_LIVE) return;
|
||||
if (SendItemUse != players[consoleplayer].ReadyWeapon && (displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
|
||||
{
|
||||
StatusBar->AttachMessage(Create<DHUDMessageFadeOut>(SmallFont, SendItemUse->GetTag(),
|
||||
1.5f, 0.90f, 0, 0, (EColorRange)*nametagcolor, 2.f, 0.35f), MAKE_ID('W', 'E', 'P', 'N'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,6 +431,7 @@ CCMD (weapnext)
|
|||
}
|
||||
|
||||
// [BC] Option to display the name of the weapon being cycled to.
|
||||
if (players[consoleplayer].playerstate != PST_LIVE) return;
|
||||
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
|
||||
{
|
||||
StatusBar->AttachMessage(Create<DHUDMessageFadeOut>(SmallFont, SendItemUse->GetTag(),
|
||||
|
@ -449,6 +458,7 @@ CCMD (weapprev)
|
|||
}
|
||||
|
||||
// [BC] Option to display the name of the weapon being cycled to.
|
||||
if (players[consoleplayer].playerstate != PST_LIVE) return;
|
||||
if ((displaynametags & 2) && StatusBar && SmallFont && SendItemUse)
|
||||
{
|
||||
StatusBar->AttachMessage(Create<DHUDMessageFadeOut>(SmallFont, SendItemUse->GetTag(),
|
||||
|
@ -1699,7 +1709,24 @@ void G_DoReborn (int playernum, bool freshbot)
|
|||
}
|
||||
else
|
||||
{
|
||||
bool isUnfriendly = players[playernum].mo && !(players[playernum].mo->flags & MF_FRIENDLY);
|
||||
bool isUnfriendly;
|
||||
|
||||
PlayerSpawnPickClass(playernum);
|
||||
|
||||
// this condition should never be false
|
||||
assert(players[playernum].cls != NULL);
|
||||
|
||||
if (players[playernum].cls != NULL)
|
||||
{
|
||||
isUnfriendly = !(GetDefaultByType(players[playernum].cls)->flags & MF_FRIENDLY);
|
||||
DPrintf(DMSG_NOTIFY, "Player class IS defined: unfriendly is %i\n", isUnfriendly);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we shouldn't be here, but if we are, get the player's current status
|
||||
isUnfriendly = players[playernum].mo && !(players[playernum].mo->flags & MF_FRIENDLY);
|
||||
DPrintf(DMSG_NOTIFY, "Player class NOT defined: unfriendly is %i\n", isUnfriendly);
|
||||
}
|
||||
|
||||
// respawn at the start
|
||||
// first disassociate the corpse
|
||||
|
|
|
@ -36,28 +36,22 @@
|
|||
#include <assert.h>
|
||||
|
||||
#include "info.h"
|
||||
#include "m_random.h"
|
||||
#include "p_local.h"
|
||||
#include "s_sound.h"
|
||||
#include "gi.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "sbar.h"
|
||||
#include "statnums.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "gstrings.h"
|
||||
#include "templates.h"
|
||||
#include "a_morph.h"
|
||||
#include "a_specialspot.h"
|
||||
#include "g_level.h"
|
||||
#include "g_game.h"
|
||||
#include "doomstat.h"
|
||||
#include "d_player.h"
|
||||
#include "p_spec.h"
|
||||
#include "serializer.h"
|
||||
#include "vm.h"
|
||||
#include "c_functions.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "vm.h"
|
||||
#include "gi.h"
|
||||
|
||||
EXTERN_CVAR(Bool, sv_unlimited_pickup)
|
||||
|
||||
|
@ -72,7 +66,8 @@ static FString StaticLastMessage;
|
|||
|
||||
void PrintPickupMessage(bool localview, const FString &str)
|
||||
{
|
||||
if (str.IsNotEmpty() && localview && (StaticLastMessageTic != gametic || StaticLastMessage.Compare(str)))
|
||||
// [MK] merge identical messages on same tic unless disabled in gameinfo
|
||||
if (str.IsNotEmpty() && localview && (gameinfo.nomergepickupmsg || StaticLastMessageTic != gametic || StaticLastMessage.Compare(str)))
|
||||
{
|
||||
StaticLastMessageTic = gametic;
|
||||
StaticLastMessage = str;
|
||||
|
|
|
@ -596,8 +596,7 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
|
|||
nextlevel = levelname;
|
||||
}
|
||||
|
||||
if (nextSkill != -1)
|
||||
NextSkill = nextSkill;
|
||||
NextSkill = (unsigned)nextSkill < AllSkills.Size() ? nextSkill : -1;
|
||||
|
||||
if (flags & CHANGELEVEL_NOINTERMISSION)
|
||||
{
|
||||
|
@ -853,6 +852,8 @@ void G_DoCompleted (void)
|
|||
// Intermission stats for entire hubs
|
||||
G_LeavingHub(mode, thiscluster, &wminfo);
|
||||
|
||||
// Do not allow playing sounds in here - they'd never be able to play properly.
|
||||
soundEngine->BlockNewSounds(true);
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
|
@ -860,6 +861,7 @@ void G_DoCompleted (void)
|
|||
G_PlayerFinishLevel (i, mode, changeflags);
|
||||
}
|
||||
}
|
||||
soundEngine->BlockNewSounds(false);
|
||||
|
||||
if (mode == FINISH_SameHub)
|
||||
{ // Remember the level's state for re-entry.
|
||||
|
|
|
@ -185,6 +185,17 @@ void DBaseDecal::SetShade (int r, int g, int b)
|
|||
AlphaColor = MAKEARGB(ColorMatcher.Pick (r, g, b), r, g, b);
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void DBaseDecal::SetTranslation(uint32_t trans)
|
||||
{
|
||||
Translation = trans;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Returns the texture the decal stuck to.
|
||||
FTextureID DBaseDecal::StickToWall (side_t *wall, double x, double y, F3DFloor *ffloor)
|
||||
{
|
||||
|
@ -585,7 +596,7 @@ void DImpactDecal::CheckMax ()
|
|||
}
|
||||
}
|
||||
|
||||
DImpactDecal *DImpactDecal::StaticCreate (const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color)
|
||||
DImpactDecal *DImpactDecal::StaticCreate (const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color, uint32_t bloodTranslation)
|
||||
{
|
||||
if (cl_maxdecals > 0)
|
||||
{
|
||||
|
@ -593,13 +604,19 @@ DImpactDecal *DImpactDecal::StaticCreate (const char *name, const DVector3 &pos,
|
|||
|
||||
if (tpl != NULL && (tpl = tpl->GetDecal()) != NULL)
|
||||
{
|
||||
return StaticCreate (tpl, pos, wall, ffloor, color);
|
||||
return StaticCreate (tpl, pos, wall, ffloor, color, bloodTranslation);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color)
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color, uint32_t bloodTranslation)
|
||||
{
|
||||
DImpactDecal *decal = NULL;
|
||||
if (tpl != NULL && cl_maxdecals > 0 && !(wall->Flags & WALLF_NOAUTODECALS))
|
||||
|
@ -613,7 +630,10 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, const DVect
|
|||
// apply the custom color as well.
|
||||
if (tpl->ShadeColor != tpl_low->ShadeColor) lowercolor=0;
|
||||
else lowercolor = color;
|
||||
StaticCreate (tpl_low, pos, wall, ffloor, lowercolor);
|
||||
|
||||
uint32_t lowerTrans = (bloodTranslation != 0 ? bloodTranslation : 0);
|
||||
|
||||
StaticCreate (tpl_low, pos, wall, ffloor, lowercolor, lowerTrans);
|
||||
}
|
||||
DImpactDecal::CheckMax();
|
||||
decal = Create<DImpactDecal>(pos.Z);
|
||||
|
@ -633,6 +653,13 @@ DImpactDecal *DImpactDecal::StaticCreate (const FDecalTemplate *tpl, const DVect
|
|||
decal->SetShade (color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
// [Nash] opaque blood
|
||||
if (bloodTranslation != 0 && tpl->ShadeColor == 0 && tpl->opaqueBlood)
|
||||
{
|
||||
decal->SetTranslation(bloodTranslation);
|
||||
decal->RenderStyle = STYLE_Normal;
|
||||
}
|
||||
|
||||
if (!cl_spreaddecals || !decal->PicNum.isValid())
|
||||
{
|
||||
return decal;
|
||||
|
@ -659,6 +686,14 @@ DBaseDecal *DImpactDecal::CloneSelf (const FDecalTemplate *tpl, double ix, doubl
|
|||
{
|
||||
tpl->ApplyToDecal (decal, wall);
|
||||
decal->AlphaColor = AlphaColor;
|
||||
|
||||
// [Nash] opaque blood
|
||||
if (tpl->ShadeColor == 0 && tpl->opaqueBlood)
|
||||
{
|
||||
decal->SetTranslation(Translation);
|
||||
decal->RenderStyle = STYLE_Normal;
|
||||
}
|
||||
|
||||
decal->RenderFlags = (decal->RenderFlags & RF_DECALMASK) |
|
||||
(this->RenderFlags & ~RF_DECALMASK);
|
||||
}
|
||||
|
@ -705,16 +740,36 @@ CCMD (spray)
|
|||
Net_WriteString (argv[1]);
|
||||
}
|
||||
|
||||
void SprayDecal(AActor *shooter, const char *name, double distance)
|
||||
void SprayDecal(AActor *shooter, const char *name, double distance, DVector3 offset, DVector3 direction)
|
||||
{
|
||||
FTraceResults trace;
|
||||
//just in case
|
||||
if (!shooter)
|
||||
return;
|
||||
|
||||
FTraceResults trace;
|
||||
DVector3 off(0, 0, 0), dir(0, 0, 0);
|
||||
|
||||
//use vanilla offset only if "custom" equal to zero
|
||||
if (offset.isZero() )
|
||||
off = shooter->PosPlusZ(shooter->Height / 2);
|
||||
|
||||
else
|
||||
off = shooter->Pos() + offset;
|
||||
|
||||
//same for direction
|
||||
if (direction.isZero() )
|
||||
{
|
||||
DAngle ang = shooter->Angles.Yaw;
|
||||
DAngle pitch = shooter->Angles.Pitch;
|
||||
double c = pitch.Cos();
|
||||
DVector3 vec(c * ang.Cos(), c * ang.Sin(), -pitch.Sin());
|
||||
dir = DVector3(c * ang.Cos(), c * ang.Sin(), -pitch.Sin());
|
||||
}
|
||||
|
||||
else
|
||||
dir = direction;
|
||||
|
||||
if (Trace(shooter->PosPlusZ(shooter->Height / 2), shooter->Sector, vec, distance, 0, ML_BLOCKEVERYTHING, shooter, trace, TRACE_NoSky))
|
||||
|
||||
if (Trace(off, shooter->Sector, dir, distance, 0, ML_BLOCKEVERYTHING, shooter, trace, TRACE_NoSky))
|
||||
{
|
||||
if (trace.HitType == TRACE_HitWall)
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@ struct F3DFloor;
|
|||
class DBaseDecal;
|
||||
|
||||
class DBaseDecal *ShootDecal(const FDecalTemplate *tpl, AActor *basisactor, sector_t *sec, double x, double y, double z, DAngle angle, double tracedist, bool permanent);
|
||||
void SprayDecal(AActor *shooter, const char *name,double distance = 172.);
|
||||
void SprayDecal(AActor *shooter, const char *name,double distance = 172., DVector3 offset = DVector3(0., 0., 0.), DVector3 direction = DVector3(0., 0., 0.) );
|
||||
|
||||
class DBaseDecal : public DThinker
|
||||
{
|
||||
|
@ -30,6 +30,7 @@ public:
|
|||
double GetRealZ (const side_t *wall) const;
|
||||
void SetShade (uint32_t rgb);
|
||||
void SetShade (int r, int g, int b);
|
||||
void SetTranslation(uint32_t trans);
|
||||
void Spread (const FDecalTemplate *tpl, side_t *wall, double x, double y, double z, F3DFloor * ffloor);
|
||||
void GetXY (side_t *side, double &x, double &y) const;
|
||||
|
||||
|
@ -63,8 +64,8 @@ public:
|
|||
DImpactDecal(double z);
|
||||
DImpactDecal (side_t *wall, const FDecalTemplate *templ);
|
||||
|
||||
static DImpactDecal *StaticCreate(const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0);
|
||||
static DImpactDecal *StaticCreate(const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0);
|
||||
static DImpactDecal *StaticCreate(const char *name, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0, uint32_t bloodTranslation = 0);
|
||||
static DImpactDecal *StaticCreate(const FDecalTemplate *tpl, const DVector3 &pos, side_t *wall, F3DFloor * ffloor, PalEntry color = 0, uint32_t bloodTranslation = 0);
|
||||
|
||||
void BeginPlay ();
|
||||
void OnDestroy() override;
|
||||
|
|
|
@ -1986,10 +1986,10 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl
|
|||
};
|
||||
|
||||
int ratio = ratioTypes[0].second;
|
||||
float distance = fabs(ratioTypes[0].first - aspect);
|
||||
float distance = fabsf(ratioTypes[0].first - aspect);
|
||||
for (int i = 1; ratioTypes[i].first != 0.0f; i++)
|
||||
{
|
||||
float d = fabs(ratioTypes[i].first - aspect);
|
||||
float d = fabsf(ratioTypes[i].first - aspect);
|
||||
if (d < distance)
|
||||
{
|
||||
ratio = ratioTypes[i].second;
|
||||
|
|
|
@ -1557,20 +1557,17 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d
|
|||
{
|
||||
bool monospaced = monospacing != EMonospacing::MOff;
|
||||
double dx = 0;
|
||||
int spacingparm = monospaced ? -spacing : spacing;
|
||||
|
||||
switch (flags & DI_TEXT_ALIGN)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case DI_TEXT_ALIGN_RIGHT:
|
||||
dx = monospaced
|
||||
? static_cast<int> ((spacing)*cstring.CharacterCount()) //monospaced, so just multiply the character size
|
||||
: static_cast<int> (font->StringWidth(cstring) + (spacing * cstring.CharacterCount()));
|
||||
dx = font->StringWidth(cstring, spacingparm);
|
||||
break;
|
||||
case DI_TEXT_ALIGN_CENTER:
|
||||
dx = monospaced
|
||||
? static_cast<int> ((spacing)*cstring.CharacterCount()) / 2 //monospaced, so just multiply the character size
|
||||
: static_cast<int> (font->StringWidth(cstring) + (spacing * cstring.CharacterCount())) / 2;
|
||||
dx = font->StringWidth(cstring, spacingparm) / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ const char* GameInfoBorders[] =
|
|||
NULL
|
||||
};
|
||||
|
||||
|
||||
#define GAMEINFOKEY_CSTRING(key, variable, length) \
|
||||
else if(nextKey.CompareNoCase(variable) == 0) \
|
||||
{ \
|
||||
|
@ -385,6 +386,7 @@ void FMapInfoParser::ParseGameInfo()
|
|||
GAMEINFOKEY_DOUBLE(telefogheight, "telefogheight")
|
||||
GAMEINFOKEY_DOUBLE(gibfactor, "gibfactor")
|
||||
GAMEINFOKEY_INT(defKickback, "defKickback")
|
||||
GAMEINFOKEY_INT(fullscreenautoaspect, "fullscreenautoaspect")
|
||||
GAMEINFOKEY_STRING(SkyFlatName, "SkyFlatName")
|
||||
GAMEINFOKEY_STRING(translator, "translator")
|
||||
GAMEINFOKEY_COLOR(pickupcolor, "pickupcolor")
|
||||
|
@ -442,6 +444,7 @@ void FMapInfoParser::ParseGameInfo()
|
|||
GAMEINFOKEY_STRING(statusscreen_dm, "statscreen_dm")
|
||||
GAMEINFOKEY_TWODOUBLES(normforwardmove, "normforwardmove")
|
||||
GAMEINFOKEY_TWODOUBLES(normsidemove, "normsidemove")
|
||||
GAMEINFOKEY_BOOL(nomergepickupmsg, "nomergepickupmsg")
|
||||
|
||||
else
|
||||
{
|
||||
|
|
|
@ -204,6 +204,8 @@ struct gameinfo_t
|
|||
int berserkpic;
|
||||
double normforwardmove[2];
|
||||
double normsidemove[2];
|
||||
int fullscreenautoaspect = 0;
|
||||
bool nomergepickupmsg;
|
||||
|
||||
const char *GetFinalePage(unsigned int num) const;
|
||||
};
|
||||
|
|
|
@ -148,7 +148,7 @@ int FLightBuffer::UploadLights(FDynLightData &data)
|
|||
else
|
||||
{
|
||||
glBufferData(mBufferType, mByteSize, NULL, GL_DYNAMIC_DRAW);
|
||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_BUFFER_BIT);
|
||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
}
|
||||
|
||||
// copy contents and delete the old buffer.
|
||||
|
@ -182,7 +182,7 @@ void FLightBuffer::Begin()
|
|||
if (gl.lightmethod == LM_DEFERRED)
|
||||
{
|
||||
glBindBuffer(mBufferType, mBufferId);
|
||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT);
|
||||
mBufferPointer = (float*)glMapBufferRange(mBufferType, 0, mByteSize, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ int FLightBuffer::BindUBO(unsigned int index)
|
|||
{
|
||||
unsigned int offset = (index / mBlockAlign) * mBlockAlign;
|
||||
|
||||
if (offset != mLastMappedIndex)
|
||||
|
||||
{
|
||||
// this will only get called if a uniform buffer is used. For a shader storage buffer we only need to bind the buffer once at the start to all shader programs
|
||||
mLastMappedIndex = offset;
|
||||
|
|
|
@ -101,10 +101,10 @@ void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms)
|
|||
if (pal) dg.mTranslation = -pal->GetIndex();
|
||||
}
|
||||
}
|
||||
u1 = gltex->GetUL();
|
||||
v1 = gltex->GetVT();
|
||||
u2 = gltex->GetUR();
|
||||
v2 = gltex->GetVB();
|
||||
u1 = parms.srcx;
|
||||
v1 = parms.srcy;
|
||||
u2 = parms.srcx + parms.srcwidth;
|
||||
v2 = parms.srcy + parms.srcheight;
|
||||
|
||||
}
|
||||
else
|
||||
|
@ -119,6 +119,8 @@ void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms)
|
|||
if (parms.flipX)
|
||||
std::swap(u1, u2);
|
||||
|
||||
if (parms.flipY)
|
||||
std::swap(v1, v2);
|
||||
|
||||
if (parms.windowleft > 0 || parms.windowright < parms.texwidth)
|
||||
{
|
||||
|
|
|
@ -110,9 +110,9 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
|
|||
mViewVector = FVector2(0,0);
|
||||
mVBO = nullptr;
|
||||
mSkyVBO = nullptr;
|
||||
mLights = nullptr;
|
||||
gl_spriteindex = 0;
|
||||
mShaderManager = nullptr;
|
||||
mLights = nullptr;
|
||||
m2DDrawer = nullptr;
|
||||
mTonemapPalette = nullptr;
|
||||
mBuffers = nullptr;
|
||||
|
@ -151,6 +151,12 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
|
|||
mSkyVBOBuff[n] = nullptr;
|
||||
}
|
||||
|
||||
mLightsBuff = new FLightBuffer*[gl_hardware_buffers];
|
||||
for(int n = 0; n < gl_hardware_buffers; n++)
|
||||
{
|
||||
mLightsBuff[n] = nullptr;
|
||||
}
|
||||
|
||||
syncBuff = new GLsync[gl_hardware_buffers];
|
||||
for(int n = 0; n < gl_hardware_buffers; n++)
|
||||
{
|
||||
|
@ -199,14 +205,13 @@ void FGLRenderer::Initialize(int width, int height)
|
|||
for (int n = 0; n < gl_hardware_buffers; n++) {
|
||||
mVBOBuff[n] = new FFlatVertexBuffer(width, height);
|
||||
mSkyVBOBuff[n] = new FSkyVertexBuffer;
|
||||
mLightsBuff[n] = new FLightBuffer;
|
||||
}
|
||||
|
||||
//Set up the VBO pointer to the first buffer
|
||||
NextVtxBuffer();
|
||||
NextSkyBuffer();
|
||||
|
||||
if (!gl.legacyMode) mLights = new FLightBuffer();
|
||||
else mLights = NULL;
|
||||
NextLightBuffer();
|
||||
|
||||
gl_RenderState.SetVertexBuffer(mVBO);
|
||||
mFBID = 0;
|
||||
|
@ -241,9 +246,16 @@ FGLRenderer::~FGLRenderer()
|
|||
delete mSkyVBOBuff[n];
|
||||
}
|
||||
if (mSkyVBOBuff) delete []mSkyVBOBuff;
|
||||
|
||||
for(int n = 0; n < gl_hardware_buffers; n++)
|
||||
{
|
||||
delete mLightsBuff[n];
|
||||
}
|
||||
if (mLightsBuff) delete []mLightsBuff;
|
||||
|
||||
|
||||
if (syncBuff) delete []syncBuff;
|
||||
|
||||
if (mLights != NULL) delete mLights;
|
||||
if (mFBID != 0) glDeleteFramebuffers(1, &mFBID);
|
||||
if (mVAOID != 0)
|
||||
{
|
||||
|
|
|
@ -65,6 +65,11 @@ inline float RAD2DEG(float deg)
|
|||
return deg * float(180. / M_PI);
|
||||
}
|
||||
|
||||
inline double RAD2DEG(double deg)
|
||||
{
|
||||
return deg * (180. / M_PI);
|
||||
}
|
||||
|
||||
enum SectorRenderFlags
|
||||
{
|
||||
// This is used to avoid creating too many drawinfos
|
||||
|
@ -158,6 +163,7 @@ public:
|
|||
|
||||
FFlatVertexBuffer **mVBOBuff;
|
||||
FSkyVertexBuffer **mSkyVBOBuff;
|
||||
FLightBuffer **mLightsBuff;
|
||||
|
||||
// Used instead of GLsync
|
||||
GLsync *syncBuff;
|
||||
|
@ -183,6 +189,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void NextLightBuffer()
|
||||
{
|
||||
mLights = mLightsBuff[LightBuff];
|
||||
if (gl_hardware_buffers > 1) {
|
||||
LightBuff++;
|
||||
LightBuff %= (int)gl_hardware_buffers;
|
||||
}
|
||||
}
|
||||
|
||||
FFlatVertexBuffer *mVBO;
|
||||
FSkyVertexBuffer *mSkyVBO;
|
||||
|
||||
|
|
|
@ -946,6 +946,7 @@ void FGLRenderer::RenderView (player_t* player)
|
|||
{
|
||||
GLRenderer->NextVtxBuffer();
|
||||
GLRenderer->NextSkyBuffer();
|
||||
GLRenderer->NextLightBuffer();
|
||||
|
||||
if (gl_sync) {
|
||||
GLRenderer->GPUWaitSync();
|
||||
|
|
|
@ -377,7 +377,7 @@ void RenderDome(FMaterial * tex, float x_offset, float y_offset, bool mirror, in
|
|||
gl_RenderState.mModelMatrix.loadIdentity();
|
||||
gl_RenderState.mModelMatrix.rotate(-180.0f + x_offset, 0.f, 1.f, 0.f);
|
||||
|
||||
float xscale = texw < 1024.f ? floor(1024.f / float(texw)) : 1.f;
|
||||
float xscale = texw < 1024.f ? floorf(1024.f / float(texw)) : 1.f;
|
||||
float yscale = 1.f;
|
||||
if (texh <= 128 && (level.flags & LEVEL_FORCETILEDSKY))
|
||||
{
|
||||
|
|
|
@ -120,6 +120,8 @@ public:
|
|||
GLWF_NOSPLITUPPER=16,
|
||||
GLWF_NOSPLITLOWER=32,
|
||||
GLWF_NOSPLIT=64,
|
||||
GLWF_TRANSLUCENT = 128, // unused
|
||||
GLWF_NOSLICE = 256
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -155,9 +157,9 @@ public:
|
|||
float ViewDistance;
|
||||
|
||||
TArray<lightlist_t> *lightlist;
|
||||
int lightlevel;
|
||||
short lightlevel;
|
||||
uint16_t flags;
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
short rellight;
|
||||
|
||||
float topglowcolor[4];
|
||||
|
|
|
@ -957,6 +957,7 @@ void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary,
|
|||
{
|
||||
tci.mRenderHeight = -tci.mRenderHeight;
|
||||
tci.mScale.Y = -tci.mScale.Y;
|
||||
flags |= GLWF_NOSLICE;
|
||||
}
|
||||
SetWallCoordinates(seg, &tci, texturetop, topleft, topright, bottomleft, bottomright, t_ofs);
|
||||
|
||||
|
@ -1017,7 +1018,7 @@ void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary,
|
|||
FloatRect *splitrect;
|
||||
int v = gltexture->GetAreas(&splitrect);
|
||||
if (seg->frontsector == seg->backsector) flags |= GLWF_NOSPLIT; // we don't need to do vertex splits if a line has both sides in the same sector
|
||||
if (v>0 && !drawfogboundary && !(seg->linedef->flags&ML_WRAP_MIDTEX))
|
||||
if (v>0 && !drawfogboundary && !(seg->linedef->flags & ML_WRAP_MIDTEX) && !(flags & GLWF_NOSLICE))
|
||||
{
|
||||
// split the poly!
|
||||
int i,t=0;
|
||||
|
@ -1194,6 +1195,7 @@ void GLWall::BuildFFBlock(seg_t * seg, F3DFloor * rover,
|
|||
lightlevel = savelight;
|
||||
Colormap = savecolor;
|
||||
flags &= ~GLT_CLAMPY;
|
||||
RenderStyle = STYLE_Normal;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2782,6 +2782,10 @@ void OpenGLSWFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms)
|
|||
{
|
||||
swapvalues(u0, u1);
|
||||
}
|
||||
if (parms.flipY)
|
||||
{
|
||||
swapvalues(v0, v1);
|
||||
}
|
||||
if (parms.windowleft > 0 || parms.windowright < parms.texwidth)
|
||||
{
|
||||
double wi = MIN(parms.windowright, parms.texwidth);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "gl/textures/gl_samplers.h"
|
||||
#include "gl/textures/gl_translate.h"
|
||||
#include "gl/models/gl_models.h"
|
||||
#include "stats.h"
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -256,7 +256,6 @@ void DIntermissionScreen::Drawer ()
|
|||
if (CheckOverlay(i))
|
||||
screen->DrawTexture (TexMan[mOverlays[i].mPic], mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, TAG_DONE);
|
||||
}
|
||||
if (!mFlatfill) screen->FillBorder (NULL);
|
||||
if (mSubtitle)
|
||||
{
|
||||
const char *sub = mSubtitle.GetChars();
|
||||
|
@ -774,7 +773,6 @@ void DIntermissionScreenScroller::Drawer ()
|
|||
DTA_Masked, false,
|
||||
TAG_DONE);
|
||||
|
||||
screen->FillBorder (NULL);
|
||||
mBackground = mSecondPic;
|
||||
}
|
||||
else
|
||||
|
@ -868,22 +866,22 @@ bool DIntermissionController::Responder (event_t *ev)
|
|||
{
|
||||
const char *cmd = Bindings.GetBind (ev->data1);
|
||||
|
||||
if (cmd != NULL &&
|
||||
(!stricmp(cmd, "toggleconsole") ||
|
||||
!stricmp(cmd, "screenshot")))
|
||||
if (cmd != nullptr)
|
||||
{
|
||||
if (!stricmp(cmd, "toggleconsole") || !stricmp(cmd, "screenshot"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// The following is needed to be able to enter main menu with a controller,
|
||||
// by pressing buttons that are usually assigned to this action, Start and Back by default
|
||||
if (!stricmp(cmd, "menu_main") || !stricmp(cmd, "pause"))
|
||||
else if (!stricmp(cmd, "menu_main") || !stricmp(cmd, "pause"))
|
||||
{
|
||||
M_StartControlPanel(true);
|
||||
M_SetMenu(NAME_Mainmenu, -1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mScreen->mTicker < 2) return false; // prevent some leftover events from auto-advancing
|
||||
int res = mScreen->Responder(ev);
|
||||
|
@ -940,6 +938,7 @@ void DIntermissionController::Drawer ()
|
|||
{
|
||||
if (mScreen != NULL)
|
||||
{
|
||||
screen->FillBorder(nullptr);
|
||||
mScreen->Drawer();
|
||||
}
|
||||
}
|
||||
|
@ -994,7 +993,11 @@ void F_StartIntermission(FIntermissionDescriptor *desc, bool deleteme, uint8_t s
|
|||
void F_StartIntermission(FName seq, uint8_t state)
|
||||
{
|
||||
FIntermissionDescriptor **pdesc = IntermissionDescriptors.CheckKey(seq);
|
||||
if (pdesc != NULL)
|
||||
if (pdesc == nullptr)
|
||||
{
|
||||
gameaction = ga_nothing;
|
||||
}
|
||||
else
|
||||
{
|
||||
F_StartIntermission(*pdesc, false, state);
|
||||
}
|
||||
|
|
|
@ -509,6 +509,7 @@ xx(Friend)
|
|||
xx(Strifeally)
|
||||
xx(Standing)
|
||||
xx(Countsecret)
|
||||
xx(NoCount)
|
||||
xx(Score)
|
||||
xx(Roll)
|
||||
xx(Scale)
|
||||
|
@ -828,6 +829,7 @@ xx(MoveBob)
|
|||
xx(StillBob)
|
||||
xx(ClassicFlight)
|
||||
xx(WBobSpeed)
|
||||
xx(WBobFire)
|
||||
xx(PlayerClass)
|
||||
xx(MonsterClass)
|
||||
xx(MorphedMonster)
|
||||
|
|
|
@ -285,6 +285,7 @@ static int P_Set3DFloor(line_t * line, int param, int param2, int alpha)
|
|||
if ((param2 & 128) && !(flags & FF_SOLID)) flags |= FF_FLOOD | FF_SEETHROUGH | FF_SHOOTTHROUGH;
|
||||
if (param2 & 512) flags |= FF_FADEWALLS;
|
||||
if (param2&1024) flags |= FF_RESET;
|
||||
if (param2 & 2048) flags |= FF_NODAMAGE;
|
||||
FTextureID tex = line->sidedef[0]->GetTexture(side_t::top);
|
||||
if (!tex.Exists() && alpha < 255)
|
||||
{
|
||||
|
@ -327,7 +328,8 @@ void P_PlayerOnSpecial3DFloor(player_t* player)
|
|||
else
|
||||
{
|
||||
//Water and DEATH FOG!!! heh
|
||||
if (player->mo->Z() > rover->top.plane->ZatPoint(player->mo) ||
|
||||
if ((rover->flags & FF_NODAMAGE) ||
|
||||
player->mo->Z() > rover->top.plane->ZatPoint(player->mo) ||
|
||||
player->mo->Top() < rover->bottom.plane->ZatPoint(player->mo))
|
||||
continue;
|
||||
}
|
||||
|
@ -900,7 +902,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
|
|||
//==========================================================================
|
||||
void P_Spawn3DFloors (void)
|
||||
{
|
||||
static int flagvals[] = {512, 2+512, 512+1024};
|
||||
static int flagvals[] = {512+2048, 2+512+2048, 512+1024+2048};
|
||||
|
||||
for (auto &line : level.lines)
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@ typedef enum
|
|||
FF_UPPERTEXTURE = 0x20000,
|
||||
FF_LOWERTEXTURE = 0x40000,
|
||||
FF_THINFLOOR = 0x80000, // EDGE
|
||||
FF_SCROLLY = 0x100000, // EDGE - not yet implemented!!!
|
||||
FF_NODAMAGE = 0x100000, // no damage transfers
|
||||
FF_FIX = 0x200000, // use floor of model sector as floor and floor of real sector as ceiling
|
||||
FF_INVERTSECTOR = 0x400000, // swap meaning of sector planes
|
||||
FF_DYNAMIC = 0x800000, // created by partitioning another 3D-floor due to overlap
|
||||
|
|
|
@ -10149,9 +10149,14 @@ scriptwait:
|
|||
else
|
||||
{
|
||||
FActorIterator iterator (tag);
|
||||
AActor *actor;
|
||||
TArray<AActor*> actorsToMorph;
|
||||
|
||||
while ( (actor = iterator.Next ()) )
|
||||
while (AActor *actor = iterator.Next())
|
||||
{
|
||||
actorsToMorph.Push(actor);
|
||||
}
|
||||
|
||||
for (AActor *actor : actorsToMorph)
|
||||
{
|
||||
changes += P_MorphActor(activator, actor, playerclass, monsterclass, duration, style, morphflash, unmorphflash);
|
||||
}
|
||||
|
@ -10175,9 +10180,14 @@ scriptwait:
|
|||
else
|
||||
{
|
||||
FActorIterator iterator (tag);
|
||||
AActor *actor;
|
||||
TArray<AActor*> actorsToUnmorph;
|
||||
|
||||
while ( (actor = iterator.Next ()) )
|
||||
while (AActor *actor = iterator.Next())
|
||||
{
|
||||
actorsToUnmorph.Push(actor);
|
||||
}
|
||||
|
||||
for (AActor *actor : actorsToUnmorph)
|
||||
{
|
||||
changes += P_UnmorphActor(activator, actor, 0, force);
|
||||
}
|
||||
|
|
|
@ -865,6 +865,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RadiusDamageSelf)
|
|||
int actualDamage;
|
||||
double actualDistance;
|
||||
|
||||
if (self->target == nullptr) return 0;
|
||||
actualDistance = self->Distance3D(self->target);
|
||||
if (actualDistance < distance)
|
||||
{
|
||||
|
@ -4958,7 +4959,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_SprayDecal)
|
|||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_STRING(name);
|
||||
PARAM_FLOAT(dist);
|
||||
SprayDecal(self, name, dist);
|
||||
PARAM_FLOAT(offset_x);
|
||||
PARAM_FLOAT(offset_y);
|
||||
PARAM_FLOAT(offset_z);
|
||||
PARAM_FLOAT(direction_x);
|
||||
PARAM_FLOAT(direction_y);
|
||||
PARAM_FLOAT(direction_z);
|
||||
SprayDecal(self, name, dist, DVector3(offset_x, offset_y, offset_z), DVector3(direction_x, direction_y, direction_z) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1021,8 +1021,8 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
|||
}
|
||||
FName MeansOfDeath = mod;
|
||||
|
||||
// Spectral targets only take damage from spectral projectiles.
|
||||
if (target->flags4 & MF4_SPECTRAL && !telefragDamage)
|
||||
// Spectral targets only take damage from spectral projectiles unless forced or telefragging.
|
||||
if ((target->flags4 & MF4_SPECTRAL) && !(flags & DMG_FORCED) && !telefragDamage)
|
||||
{
|
||||
if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL))
|
||||
{
|
||||
|
|
|
@ -3409,12 +3409,6 @@ FUNC(LS_Line_SetPortalTarget)
|
|||
FUNC(LS_Sector_SetPlaneReflection)
|
||||
// Sector_SetPlaneReflection (tag, floor, ceiling)
|
||||
{
|
||||
if (!gl_plane_reflection_i)
|
||||
{
|
||||
//If no reflections, just return
|
||||
return true;
|
||||
}
|
||||
|
||||
int secnum;
|
||||
FSectorTagIterator itr(arg0);
|
||||
|
||||
|
@ -3922,6 +3916,13 @@ int P_FindLineSpecial (const char *string, int *min_args, int *max_args)
|
|||
max = mid - 1;
|
||||
}
|
||||
}
|
||||
// Alias for ZScript. Check here to have universal support everywhere.
|
||||
if (!stricmp(string, "TeleportSpecial"))
|
||||
{
|
||||
if (min_args != NULL) *min_args = 1;
|
||||
if (max_args != NULL) *max_args = 3;
|
||||
return Teleport;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ void P_PredictionLerpReset();
|
|||
#define SPF_TEMPPLAYER 1 // spawning a short-lived dummy player
|
||||
#define SPF_WEAPONFULLYUP 2 // spawn with weapon already raised
|
||||
|
||||
void PlayerSpawnPickClass (int playernum);
|
||||
AActor *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags=0);
|
||||
|
||||
int P_FaceMobj (AActor *source, AActor *target, DAngle *delta);
|
||||
|
@ -259,6 +260,7 @@ extern TArray<spechit_t> portalhit;
|
|||
int P_TestMobjLocation (AActor *mobj);
|
||||
int P_TestMobjZ (AActor *mobj, bool quick=true, AActor **pOnmobj = NULL);
|
||||
bool P_CheckPosition(AActor *thing, const DVector2 &pos, bool actorsonly = false);
|
||||
void P_DoMissileDamage(AActor* inflictor, AActor* target);
|
||||
bool P_CheckPosition(AActor *thing, const DVector2 &pos, FCheckPosition &tm, bool actorsonly = false);
|
||||
AActor *P_CheckOnmobj (AActor *thing);
|
||||
void P_FakeZMovement (AActor *mo);
|
||||
|
|
|
@ -1242,6 +1242,57 @@ static bool CanAttackHurt(AActor *victim, AActor *shooter)
|
|||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// P_DoMissileDamage
|
||||
// Handle damaging/poisoning enemies from missiles.
|
||||
// target is the target to be dealt damage to.
|
||||
// inflictor is the actor dealing the damage.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void P_DoMissileDamage(AActor* inflictor, AActor* target)
|
||||
{
|
||||
// Do poisoning (if using new style poison)
|
||||
if (inflictor->PoisonDamage > 0 && inflictor->PoisonDuration != INT_MIN)
|
||||
{
|
||||
P_PoisonMobj(target, inflictor, inflictor->target, inflictor->PoisonDamage, inflictor->PoisonDuration, inflictor->PoisonPeriod, inflictor->PoisonDamageType);
|
||||
}
|
||||
|
||||
// Do damage
|
||||
int damage = inflictor->GetMissileDamage((inflictor->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1);
|
||||
if ((damage > 0) || (inflictor->flags6 & MF6_FORCEPAIN) || (inflictor->flags7 & MF7_CAUSEPAIN))
|
||||
{
|
||||
int newdam = P_DamageMobj(target, inflictor, inflictor->target, damage, inflictor->DamageType);
|
||||
if (damage > 0)
|
||||
{
|
||||
if ((inflictor->flags5 & MF5_BLOODSPLATTER) &&
|
||||
!(target->flags & MF_NOBLOOD) &&
|
||||
!(target->flags2 & MF2_REFLECTIVE) &&
|
||||
!(target->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)) &&
|
||||
!(inflictor->flags3 & MF3_BLOODLESSIMPACT) &&
|
||||
(pr_checkthing() < 192))
|
||||
{
|
||||
P_BloodSplatter(inflictor->Pos(), target, inflictor->AngleTo(target));
|
||||
}
|
||||
if (!(inflictor->flags3 & MF3_BLOODLESSIMPACT))
|
||||
{
|
||||
P_TraceBleed(newdam > 0 ? newdam : damage, target, inflictor);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_GiveBody(target, -damage);
|
||||
}
|
||||
}
|
||||
DEFINE_ACTION_FUNCTION(AActor, DoMissileDamage)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_OBJECT_NOT_NULL(target, AActor);
|
||||
P_DoMissileDamage(self, target);
|
||||
return 0;
|
||||
}
|
||||
//==========================================================================
|
||||
//
|
||||
// PIT_CheckThing
|
||||
|
@ -1567,38 +1618,7 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch
|
|||
}
|
||||
}
|
||||
|
||||
// Do poisoning (if using new style poison)
|
||||
if (tm.thing->PoisonDamage > 0 && tm.thing->PoisonDuration != INT_MIN)
|
||||
{
|
||||
P_PoisonMobj(thing, tm.thing, tm.thing->target, tm.thing->PoisonDamage, tm.thing->PoisonDuration, tm.thing->PoisonPeriod, tm.thing->PoisonDamageType);
|
||||
}
|
||||
|
||||
// Do damage
|
||||
damage = tm.thing->GetMissileDamage((tm.thing->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1);
|
||||
if ((damage > 0) || (tm.thing->flags6 & MF6_FORCEPAIN) || (tm.thing->flags7 & MF7_CAUSEPAIN))
|
||||
{
|
||||
int newdam = P_DamageMobj(thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType);
|
||||
if (damage > 0)
|
||||
{
|
||||
if ((tm.thing->flags5 & MF5_BLOODSPLATTER) &&
|
||||
!(thing->flags & MF_NOBLOOD) &&
|
||||
!(thing->flags2 & MF2_REFLECTIVE) &&
|
||||
!(thing->flags2 & (MF2_INVULNERABLE | MF2_DORMANT)) &&
|
||||
!(tm.thing->flags3 & MF3_BLOODLESSIMPACT) &&
|
||||
(pr_checkthing() < 192))
|
||||
{
|
||||
P_BloodSplatter(tm.thing->Pos(), thing, tm.thing->AngleTo(thing));
|
||||
}
|
||||
if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT))
|
||||
{
|
||||
P_TraceBleed(newdam > 0 ? newdam : damage, thing, tm.thing);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_GiveBody(thing, -damage);
|
||||
}
|
||||
P_DoMissileDamage(tm.thing, thing);
|
||||
|
||||
if ((thing->flags7 & MF7_THRUREFLECT) && (thing->flags2 & MF2_REFLECTIVE) && (tm.thing->flags & MF_MISSILE))
|
||||
{
|
||||
|
@ -4916,7 +4936,8 @@ int P_LineTrace(AActor *t1, DAngle angle, double distance,
|
|||
outdata->HitLocation = trace.HitPos;
|
||||
outdata->HitDir = trace.HitVector;
|
||||
outdata->Distance = trace.Distance;
|
||||
outdata->NumPortals = TData.NumPortals;
|
||||
// [MK] Subtract two "bogus" portal crossings used internally by trace code
|
||||
outdata->NumPortals = TData.NumPortals-2;
|
||||
outdata->HitType = trace.HitType;
|
||||
}
|
||||
return ret;
|
||||
|
@ -5037,8 +5058,10 @@ void P_TraceBleed(int damage, const DVector3 &pos, AActor *actor, DAngle angle,
|
|||
bloodcolor.a = 1;
|
||||
}
|
||||
|
||||
uint32_t bloodTrans = (bloodcolor != 0 ? actor->BloodTranslation : 0);
|
||||
|
||||
DImpactDecal::StaticCreate(bloodType, bleedtrace.HitPos,
|
||||
bleedtrace.Line->sidedef[bleedtrace.Side], bleedtrace.ffloor, bloodcolor);
|
||||
bleedtrace.Line->sidedef[bleedtrace.Side], bleedtrace.ffloor, bloodcolor, bloodTrans);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3992,6 +3992,7 @@ void AActor::Tick ()
|
|||
// to be in line with the case when an actor's side is hit.
|
||||
if (!res && (flags & MF_MISSILE))
|
||||
{
|
||||
P_DoMissileDamage(this, onmo);
|
||||
P_ExplodeMissile(this, nullptr, onmo);
|
||||
}
|
||||
}
|
||||
|
@ -4565,7 +4566,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
if (level.flags & LEVEL_NOALLIES && !actor->player)
|
||||
if (level.flags & LEVEL_NOALLIES && !actor->IsKindOf(NAME_PlayerPawn))
|
||||
{
|
||||
actor->flags &= ~MF_FRIENDLY;
|
||||
}
|
||||
|
@ -4672,6 +4673,19 @@ void AActor::HandleSpawnFlags ()
|
|||
level.total_secrets++;
|
||||
}
|
||||
}
|
||||
if (SpawnFlags & MTF_NOCOUNT)
|
||||
{
|
||||
if (flags & MF_COUNTKILL)
|
||||
{
|
||||
flags &= ~MF_COUNTKILL;
|
||||
level.total_monsters--;
|
||||
}
|
||||
if (flags & MF_COUNTITEM)
|
||||
{
|
||||
flags &= ~MF_COUNTITEM;
|
||||
level.total_items--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, HandleSpawnFlags)
|
||||
|
@ -4878,9 +4892,6 @@ void AActor::AdjustFloorClip ()
|
|||
double shallowestclip = INT_MAX;
|
||||
const msecnode_t *m;
|
||||
|
||||
// possibly standing on a 3D-floor
|
||||
if (Sector->e->XFloor.ffloors.Size() && Z() > Sector->floorplane.ZatPoint(this)) Floorclip = 0;
|
||||
|
||||
// [RH] clip based on shallowest floor player is standing on
|
||||
// If the sector has a deep water effect, then let that effect
|
||||
// do the floorclipping instead of the terrain type.
|
||||
|
@ -4888,7 +4899,9 @@ void AActor::AdjustFloorClip ()
|
|||
{
|
||||
DVector3 pos = PosRelative(m->m_sector);
|
||||
sector_t *hsec = m->m_sector->GetHeightSec();
|
||||
if (hsec == NULL && m->m_sector->floorplane.ZatPoint (pos) == Z())
|
||||
if (hsec == NULL)
|
||||
{
|
||||
if (m->m_sector->floorplane.ZatPoint(pos) == Z())
|
||||
{
|
||||
double clip = Terrains[m->m_sector->GetTerrain(sector_t::floor)].FootClip;
|
||||
if (clip < shallowestclip)
|
||||
|
@ -4896,6 +4909,22 @@ void AActor::AdjustFloorClip ()
|
|||
shallowestclip = clip;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& ff : m->m_sector->e->XFloor.ffloors)
|
||||
{
|
||||
if ((ff->flags & FF_SOLID) && (ff->flags & FF_EXISTS) && ff->top.plane->ZatPoint(pos) == Z())
|
||||
{
|
||||
double clip = Terrains[ff->top.model->GetTerrain(ff->top.isceiling)].FootClip;
|
||||
if (clip < shallowestclip)
|
||||
{
|
||||
shallowestclip = clip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shallowestclip == INT_MAX)
|
||||
{
|
||||
|
@ -4931,29 +4960,9 @@ extern "C" float QzDoom_GetFOV();
|
|||
|
||||
extern bool demonew;
|
||||
|
||||
AActor *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
|
||||
void PlayerSpawnPickClass (int playernum)
|
||||
{
|
||||
player_t *p;
|
||||
AActor *mobj, *oldactor;
|
||||
uint8_t state;
|
||||
DVector3 spawn;
|
||||
DAngle SpawnAngle;
|
||||
|
||||
if (mthing == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
// not playing?
|
||||
if ((unsigned)playernum >= (unsigned)MAXPLAYERS || !playeringame[playernum])
|
||||
return NULL;
|
||||
|
||||
// Old lerp data needs to go
|
||||
if (playernum == consoleplayer)
|
||||
{
|
||||
P_PredictionLerpReset();
|
||||
}
|
||||
|
||||
p = &players[playernum];
|
||||
auto p = &players[playernum];
|
||||
|
||||
if (p->cls == NULL)
|
||||
{
|
||||
|
@ -4982,6 +4991,33 @@ AActor *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
|
|||
}
|
||||
p->cls = PlayerClasses[p->CurrentPlayerClass].Type;
|
||||
}
|
||||
}
|
||||
|
||||
AActor *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
|
||||
{
|
||||
player_t *p;
|
||||
AActor *mobj, *oldactor;
|
||||
uint8_t state;
|
||||
DVector3 spawn;
|
||||
DAngle SpawnAngle;
|
||||
|
||||
if (mthing == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
// not playing?
|
||||
if ((unsigned)playernum >= (unsigned)MAXPLAYERS || !playeringame[playernum])
|
||||
return NULL;
|
||||
|
||||
// Old lerp data needs to go
|
||||
if (playernum == consoleplayer)
|
||||
{
|
||||
P_PredictionLerpReset();
|
||||
}
|
||||
|
||||
p = &players[playernum];
|
||||
|
||||
PlayerSpawnPickClass(playernum);
|
||||
|
||||
if (( dmflags2 & DF2_SAME_SPAWN_SPOT ) &&
|
||||
( p->playerstate == PST_REBORN ) &&
|
||||
|
@ -5483,6 +5519,11 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
|
|||
else if (sz == ONCEILINGZ)
|
||||
mobj->AddZ(-mthing->pos.Z);
|
||||
|
||||
if (mobj->flags2 & MF2_FLOORCLIP)
|
||||
{
|
||||
mobj->AdjustFloorClip();
|
||||
}
|
||||
|
||||
mobj->SpawnPoint = mthing->pos;
|
||||
mobj->SpawnAngle = mthing->angle;
|
||||
mobj->SpawnFlags = mthing->flags;
|
||||
|
@ -7306,14 +7347,15 @@ void AActor::ClearCounters()
|
|||
int AActor::GetModifiedDamage(FName damagetype, int damage, bool passive, AActor *inflictor, AActor *source, int flags)
|
||||
{
|
||||
auto inv = Inventory;
|
||||
while (inv != nullptr)
|
||||
while (inv != nullptr && !(inv->ObjectFlags & OF_EuthanizeMe))
|
||||
{
|
||||
auto nextinv = inv->Inventory;
|
||||
IFVIRTUALPTRNAME(inv, NAME_Inventory, ModifyDamage)
|
||||
{
|
||||
VMValue params[8] = { (DObject*)inv, damage, int(damagetype), &damage, passive, inflictor, source, flags };
|
||||
VMCall(func, params, 8, nullptr, 0);
|
||||
}
|
||||
inv = inv->Inventory;
|
||||
inv = nextinv;
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
|
|
|
@ -233,7 +233,8 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, FindPSprite) // the underscore is needed to
|
|||
void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending)
|
||||
{
|
||||
if (player == nullptr) return;
|
||||
player->GetPSprite(id)->SetState(state, pending);
|
||||
auto psp = player->GetPSprite(id);
|
||||
if (psp) psp->SetState(state, pending);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_PlayerInfo, SetPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit)
|
||||
|
@ -267,7 +268,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer)
|
|||
newcaller = ReadyWeapon;
|
||||
}
|
||||
|
||||
assert(newcaller != nullptr);
|
||||
if (newcaller == nullptr) return nullptr; // Error case was not handled properly. This function cannot give a guarantee to always succeed!
|
||||
|
||||
DPSprite *pspr = FindPSprite(layer);
|
||||
if (pspr == nullptr)
|
||||
|
|
|
@ -1717,6 +1717,7 @@ void P_LoadLineDefs (MapData * map)
|
|||
|
||||
auto mldf = map->Read(ML_LINEDEFS);
|
||||
int numlines = mldf.Size() / sizeof(maplinedef_t);
|
||||
int numsides = map->Size(ML_SIDEDEFS) / sizeof(mapsidedef_t);
|
||||
linemap.Resize(numlines);
|
||||
|
||||
// [RH] Count the number of sidedef references. This is the number of
|
||||
|
@ -1744,13 +1745,6 @@ void P_LoadLineDefs (MapData * map)
|
|||
}
|
||||
else
|
||||
{
|
||||
// patch missing first sides instead of crashing out.
|
||||
// Visual glitches are better than not being able to play.
|
||||
if (LittleShort(mld->sidenum[0]) == NO_INDEX)
|
||||
{
|
||||
Printf("Line %d has no first side.\n", i);
|
||||
mld->sidenum[0] = 0;
|
||||
}
|
||||
sidecount++;
|
||||
if (LittleShort(mld->sidenum[1]) != NO_INDEX)
|
||||
sidecount++;
|
||||
|
@ -1789,6 +1783,22 @@ void P_LoadLineDefs (MapData * map)
|
|||
ProcessEDLinedef(ld, mld->tag);
|
||||
}
|
||||
#endif
|
||||
// cph 2006/09/30 - fix sidedef errors right away.
|
||||
for (int j=0; j < 2; j++)
|
||||
{
|
||||
if (LittleShort(mld->sidenum[j]) != NO_INDEX && mld->sidenum[j] >= numsides)
|
||||
{
|
||||
mld->sidenum[j] = 0; // dummy sidedef
|
||||
Printf("Linedef %d has a bad sidedef\n", i);
|
||||
}
|
||||
}
|
||||
// patch missing first sides instead of crashing out.
|
||||
// Visual glitches are better than not being able to play.
|
||||
if (LittleShort(mld->sidenum[0]) == NO_INDEX)
|
||||
{
|
||||
Printf("Line %d has no first side.\n", i);
|
||||
mld->sidenum[0] = 0;
|
||||
}
|
||||
|
||||
ld->v1 = &level.vertexes[LittleShort(mld->v1)];
|
||||
ld->v2 = &level.vertexes[LittleShort(mld->v2)];
|
||||
|
@ -2261,11 +2271,11 @@ void P_LoadSideDefs2 (MapData *map, FMissingTextureTracker &missingtex)
|
|||
// killough 4/4/98: allow sidedef texture names to be overloaded
|
||||
// killough 4/11/98: refined to allow colormaps to work as wall
|
||||
// textures if invalid as colormaps but valid as textures.
|
||||
|
||||
// cph 2006/09/30 - catch out-of-range sector numbers; use sector 0 instead
|
||||
if ((unsigned)LittleShort(msd->sector)>=level.sectors.Size())
|
||||
{
|
||||
Printf (PRINT_HIGH, "Sidedef %d has a bad sector\n", i);
|
||||
sd->sector = sec = NULL;
|
||||
sd->sector = sec = &level.sectors[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -274,7 +274,7 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType,
|
|||
{
|
||||
int lineActivation = line->activation;
|
||||
|
||||
if (line->flags & ML_FIRSTSIDEONLY && side == 1)
|
||||
if ((line->flags & ML_FIRSTSIDEONLY && side == 1) || line->special == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -457,6 +457,9 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
|
|||
// Has hit ground.
|
||||
AActor *ironfeet;
|
||||
|
||||
if (sector->damageinterval == 0)
|
||||
sector->damageinterval = 32;
|
||||
|
||||
// [RH] Apply any customizable damage
|
||||
if (sector->damageamount > 0)
|
||||
{
|
||||
|
@ -651,7 +654,7 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GiveSecret)
|
|||
void P_PlayerOnSpecialFlat (player_t *player, int floorType)
|
||||
{
|
||||
if (Terrains[floorType].DamageAmount &&
|
||||
!(level.time & Terrains[floorType].DamageTimeMask))
|
||||
!(level.time % (Terrains[floorType].DamageTimeMask+1)))
|
||||
{
|
||||
AActor *ironfeet = NULL;
|
||||
|
||||
|
|
|
@ -272,6 +272,7 @@ static void MakeDefaultTerrain ()
|
|||
|
||||
def.Name = "Solid";
|
||||
def.Splash = -1;
|
||||
def.DamageTimeMask = 31;
|
||||
Terrains.Push (def);
|
||||
}
|
||||
|
||||
|
@ -434,6 +435,7 @@ void ParseTerrain (FScanner &sc)
|
|||
memset (&def, 0, sizeof(def));
|
||||
def.Splash = -1;
|
||||
def.Name = name;
|
||||
def.DamageTimeMask = 31;
|
||||
terrainnum = (int)Terrains.Push (def);
|
||||
}
|
||||
|
||||
|
@ -445,6 +447,7 @@ void ParseTerrain (FScanner &sc)
|
|||
memset (&Terrains[terrainnum], 0, sizeof(FTerrainDef));
|
||||
Terrains[terrainnum].Splash = -1;
|
||||
Terrains[terrainnum].Name = name;
|
||||
Terrains[terrainnum].DamageTimeMask = 31;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -853,7 +853,7 @@ bool FTraceInfo::TraceTraverse (int ptflags)
|
|||
}
|
||||
if (!LineCheck(in, dist, hit, false)) break;
|
||||
}
|
||||
else if ((in->d.thing->flags & ActorMask) && in->d.thing != IgnoreThis)
|
||||
else if (((in->d.thing->flags & ActorMask) || ActorMask == 0xffffffff) && in->d.thing != IgnoreThis)
|
||||
{
|
||||
if (!ThingCheck(in, dist, hit)) break;
|
||||
}
|
||||
|
|
|
@ -660,6 +660,11 @@ public:
|
|||
Flag(th->flags, MTF_SECRET, key);
|
||||
break;
|
||||
|
||||
case NAME_NoCount:
|
||||
CHECK_N(Zd | Zdt)
|
||||
Flag(th->flags, MTF_NOCOUNT, key);
|
||||
break;
|
||||
|
||||
case NAME_Floatbobphase:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->FloatbobPhase = CheckInt(key);
|
||||
|
|
|
@ -810,6 +810,12 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetWBobSpeed)
|
|||
ACTION_RETURN_FLOAT(self->userinfo.GetWBobSpeed());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetWBobFire)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(player_t);
|
||||
ACTION_RETURN_FLOAT(self->userinfo.GetWBobFire());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetMoveBob)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(player_t);
|
||||
|
|
|
@ -572,6 +572,7 @@ bool EV_MovePolyTo(line_t *line, int polyNum, double speed, const DVector2 &targ
|
|||
pe->m_Speed = speed;
|
||||
pe->m_Speedv = dist * speed;
|
||||
pe->m_Target = poly->StartSpot.pos + dist * distlen;
|
||||
SN_StartSequence(poly, poly->seqType, SEQ_DOOR, 0);
|
||||
if ((pe->m_Dist / pe->m_Speed) <= 2)
|
||||
{
|
||||
pe->StopInterpolation();
|
||||
|
|
|
@ -97,7 +97,7 @@ void I_ShutdownJoysticks();
|
|||
|
||||
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
||||
|
||||
static void DeleteStartupScreen();
|
||||
void DeleteStartupScreen();
|
||||
|
||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||
|
||||
|
@ -139,7 +139,7 @@ FStartupScreen *FStartupScreen::CreateInstance(int max_progress)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
static void DeleteStartupScreen()
|
||||
void DeleteStartupScreen()
|
||||
{
|
||||
if (StartScreen != NULL)
|
||||
{
|
||||
|
|
|
@ -407,15 +407,13 @@ void FResourceFile::PostProcessArchive(void *lumps, size_t lumpsize)
|
|||
long len;
|
||||
int lastpos = -1;
|
||||
FString file;
|
||||
if (LumpFilterIWAD.IndexOf('.') < 0)
|
||||
{
|
||||
max -= FilterLumps(LumpFilterIWAD, lumps, lumpsize, max);
|
||||
}
|
||||
else while ((len = LumpFilterIWAD.IndexOf('.', lastpos+1)) > 0)
|
||||
while ((len = LumpFilterIWAD.IndexOf('.', lastpos+1)) > 0)
|
||||
{
|
||||
max -= FilterLumps(LumpFilterIWAD.Left(len), lumps, lumpsize, max);
|
||||
lastpos = len;
|
||||
}
|
||||
max -= FilterLumps(LumpFilterIWAD, lumps, lumpsize, max);
|
||||
|
||||
JunkLeftoverFilters(lumps, lumpsize, max);
|
||||
}
|
||||
|
||||
|
|
|
@ -6485,7 +6485,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
|||
if (Object->ValueType->isRealPointer())
|
||||
{
|
||||
auto ptype = Object->ValueType->toPointer()->PointedType;
|
||||
if (ptype->isContainer())
|
||||
if (ptype && ptype->isContainer())
|
||||
{
|
||||
auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast<PContainerType *>(ptype));
|
||||
delete this;
|
||||
|
|
|
@ -484,7 +484,7 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
|||
// Otherwise, it's a sequence of actions.
|
||||
if (!sc.Compare("{"))
|
||||
{
|
||||
FxVMFunctionCall *call = ParseAction(sc, state, statestring, bag);
|
||||
FxExpression *call = ParseAction(sc, state, statestring, bag);
|
||||
endswithret = true;
|
||||
return new FxReturnStatement(call, sc);
|
||||
}
|
||||
|
@ -568,14 +568,12 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag)
|
||||
FxExpression* ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag)
|
||||
{
|
||||
FxVMFunctionCall *call;
|
||||
|
||||
// Make the action name lowercase
|
||||
strlwr (sc.String);
|
||||
|
||||
call = DoActionSpecials(sc, state, bag);
|
||||
FxExpression *call = DoActionSpecials(sc, state, bag);
|
||||
if (call != NULL)
|
||||
{
|
||||
return call;
|
||||
|
@ -588,7 +586,7 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B
|
|||
{
|
||||
FArgumentList args;
|
||||
ParseFunctionParameters(sc, bag.Info, args, afd, statestring, &bag.statedef);
|
||||
call = new FxVMFunctionCall(new FxSelf(sc), afd, args, sc, false);
|
||||
call = new FxFunctionCall(symname, NAME_None, args, sc);
|
||||
return call;
|
||||
}
|
||||
sc.ScriptError("Invalid parameter '%s'\n", sc.String);
|
||||
|
|
|
@ -590,7 +590,9 @@ void RemoveUnusedSymbols()
|
|||
PSymbolTable::MapType::Pair *pair;
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
if (!pair->Value->IsKindOf(RUNTIME_CLASS(PField)) && !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction)))
|
||||
if ( !pair->Value->IsKindOf(RUNTIME_CLASS(PField))
|
||||
&& !pair->Value->IsKindOf(RUNTIME_CLASS(PFunction))
|
||||
&& !pair->Value->IsKindOf(RUNTIME_CLASS(PPropFlag)) )
|
||||
{
|
||||
ty->Symbols.RemoveSymbol(pair->Value);
|
||||
count++;
|
||||
|
|
|
@ -200,7 +200,7 @@ void ParseStates(FScanner &sc, PClassActor *actor, AActor *defaults, Baggage &ba
|
|||
void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray<FxExpression *> &out_params,
|
||||
PFunction *afd, FString statestring, FStateDefinitions *statedef);
|
||||
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag, bool &endswithret);
|
||||
class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag);
|
||||
FxExpression *ParseAction(FScanner &sc, FState state, FString statestring, Baggage &bag);
|
||||
FName CheckCastKludges(FName in);
|
||||
void SetImplicitArgs(TArray<PType *> *args, TArray<uint32_t> *argflags, TArray<FName> *argnames, PContainerType *cls, uint32_t funcflags, int useflags);
|
||||
PFunction *CreateAnonymousFunction(PContainerType *containingclass, PType *returntype, int flags);
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
#include "d_event.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "p_checkposition.h"
|
||||
#include "r_sky.h"
|
||||
#include "p_linetracedata.h"
|
||||
#include "v_font.h"
|
||||
#include "v_video.h"
|
||||
#include "c_bind.h"
|
||||
|
@ -851,21 +851,6 @@ void InitThingdef()
|
|||
wbplayerstruct->Size = sizeof(wbplayerstruct_t);
|
||||
wbplayerstruct->Align = alignof(wbplayerstruct_t);
|
||||
|
||||
auto dictionarystruct = NewStruct("Dictionary", nullptr, true);
|
||||
dictionarystruct->Size = sizeof(Dictionary);
|
||||
dictionarystruct->Align = alignof(Dictionary);
|
||||
NewPointer(dictionarystruct, false)->InstallHandlers(
|
||||
[](FSerializer &ar, const char *key, const void *addr)
|
||||
{
|
||||
ar(key, *(Dictionary **)addr);
|
||||
},
|
||||
[](FSerializer &ar, const char *key, void *addr)
|
||||
{
|
||||
Serialize<Dictionary>(ar, key, *(Dictionary **)addr, nullptr);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
FAutoSegIterator probe(CRegHead, CRegTail);
|
||||
|
||||
while (*++probe != NULL)
|
||||
|
@ -926,6 +911,9 @@ void InitThingdef()
|
|||
frp->Size = sizeof(FRailParams);
|
||||
frp->Align = alignof(FRailParams);
|
||||
|
||||
auto fltd = NewStruct("FLineTraceData", nullptr);
|
||||
fltd->Size = sizeof(FLineTraceData);
|
||||
fltd->Align = alignof(FLineTraceData);
|
||||
|
||||
FieldTable.Clear();
|
||||
if (FieldTable.Size() == 0)
|
||||
|
|
|
@ -276,7 +276,7 @@ void JitCompiler::SetupFrame()
|
|||
offsetD = offsetA + (int)(sfunc->NumRegA * sizeof(void*));
|
||||
offsetExtra = (offsetD + (int)(sfunc->NumRegD * sizeof(int32_t)) + 15) & ~15;
|
||||
|
||||
if (sfunc->SpecialInits.Size() == 0 && sfunc->NumRegS == 0)
|
||||
if (sfunc->SpecialInits.Size() == 0 && sfunc->NumRegS == 0 && sfunc->ExtraSpace == 0)
|
||||
{
|
||||
SetupSimpleFrame();
|
||||
}
|
||||
|
@ -389,7 +389,7 @@ static void PopFullVMFrame(VMFrameStack *stack)
|
|||
|
||||
void JitCompiler::EmitPopFrame()
|
||||
{
|
||||
if (sfunc->SpecialInits.Size() != 0 || sfunc->NumRegS != 0)
|
||||
if (sfunc->SpecialInits.Size() != 0 || sfunc->NumRegS != 0 || sfunc->ExtraSpace != 0)
|
||||
{
|
||||
auto popFrame = CreateCall<void, VMFrameStack *>(PopFullVMFrame);
|
||||
popFrame->setArg(0, stack);
|
||||
|
|
|
@ -142,6 +142,15 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StopSound, NativeStopSound)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StopSounds, S_StopActorSounds)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT(chanmin);
|
||||
PARAM_INT(chanmax);
|
||||
S_StopActorSounds(self, chanmin, chanmax);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SoundPitch, S_ChangeActorSoundPitch)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
@ -183,7 +192,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StartSound, A_StartSound)
|
|||
PARAM_FLOAT(volume);
|
||||
PARAM_FLOAT(attenuation);
|
||||
PARAM_FLOAT(pitch);
|
||||
A_StartSound(self, soundid, channel, flags, volume, attenuation, pitch);
|
||||
PARAM_FLOAT(startTime);
|
||||
A_StartSound(self, soundid, channel, flags, volume, attenuation, pitch, startTime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1599,6 +1609,22 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, Substitute, DObject::StaticPointerSubstitu
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_PlayerPawn, Substitute, DObject::StaticPointerSubstitution)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_OBJECT(replace, AActor);
|
||||
DObject::StaticPointerSubstitution(self, replace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(_MorphedMonster, Substitute, DObject::StaticPointerSubstitution)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_OBJECT(replace, AActor);
|
||||
DObject::StaticPointerSubstitution(self, replace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetSpawnableType, P_GetSpawnableType)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
|
@ -1614,6 +1640,23 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_NoBlocking, A_Unblock)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void CopyBloodColor(AActor* self, AActor* other)
|
||||
{
|
||||
if (self && other)
|
||||
{
|
||||
self->BloodColor = other->BloodColor;
|
||||
self->BloodTranslation = other->BloodTranslation;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(AActor, CopyBloodColor, CopyBloodColor)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_OBJECT(other, AActor);
|
||||
CopyBloodColor(self, other);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
// Inventory exports
|
||||
|
@ -1941,6 +1984,7 @@ DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitSector);
|
|||
DEFINE_FIELD_X(FLineTraceData, FLineTraceData, Hit3DFloor);
|
||||
DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitTexture);
|
||||
DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitLocation);
|
||||
DEFINE_FIELD_X(FLineTraceData, FLineTraceData, HitDir);
|
||||
DEFINE_FIELD_X(FLineTraceData, FLineTraceData, Distance);
|
||||
DEFINE_FIELD_X(FLineTraceData, FLineTraceData, NumPortals);
|
||||
DEFINE_FIELD_X(FLineTraceData, FLineTraceData, LineSide);
|
||||
|
|
|
@ -914,6 +914,25 @@ static void PrintPropertyStmt(FLispString &out, ZCC_TreeNode *node)
|
|||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintMixinDef(FLispString &out, ZCC_TreeNode *node)
|
||||
{
|
||||
ZCC_MixinDef *mdnode = (ZCC_MixinDef *)node;
|
||||
out.Break();
|
||||
out.Open("mixin-def");
|
||||
out.AddName(mdnode->NodeName);
|
||||
PrintNodes(out, mdnode->Body);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
static void PrintMixinStmt(FLispString &out, ZCC_TreeNode *node)
|
||||
{
|
||||
ZCC_MixinStmt *msnode = (ZCC_MixinStmt *)node;
|
||||
out.Break();
|
||||
out.Open("mixin-stmt");
|
||||
out.AddName(msnode->MixinName);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *) =
|
||||
{
|
||||
PrintIdentifier,
|
||||
|
@ -973,6 +992,8 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *
|
|||
PrintStaticArrayState,
|
||||
PrintProperty,
|
||||
PrintFlagDef,
|
||||
PrintMixinDef,
|
||||
PrintMixinStmt,
|
||||
};
|
||||
|
||||
FString ZCC_PrintAST(ZCC_TreeNode *root)
|
||||
|
|
|
@ -1563,9 +1563,7 @@ bool ZCCCompiler::CompileFields(PContainerType *type, TArray<ZCC_VarDeclarator *
|
|||
f = type->AddField(name->Name, thisfieldtype, varflags);
|
||||
}
|
||||
|
||||
assert(f != nullptr);
|
||||
|
||||
if (field->Flags & (ZCC_Version | ZCC_Deprecated))
|
||||
if ((field->Flags & (ZCC_Version | ZCC_Deprecated)) && f != nullptr)
|
||||
{
|
||||
f->mVersion = field->Version;
|
||||
|
||||
|
@ -3411,7 +3409,6 @@ void ZCCCompiler::CompileStates()
|
|||
if (!statedef.SetWait())
|
||||
{
|
||||
Error(st, "%s before first state", st->NodeType == AST_StateFail ? "Fail" : "Wait");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -3419,7 +3416,6 @@ void ZCCCompiler::CompileStates()
|
|||
if (!statedef.SetLoop())
|
||||
{
|
||||
Error(st, "LOOP before first state");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -2109,7 +2109,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon
|
|||
FString DictionaryToString(const Dictionary &dict)
|
||||
{
|
||||
Dictionary::ConstPair *pair;
|
||||
Dictionary::ConstIterator i { dict };
|
||||
Dictionary::ConstIterator i { dict.Map };
|
||||
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
|
@ -2134,7 +2134,7 @@ Dictionary *DictionaryFromString(const FString &string)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Dictionary *const dict = new Dictionary;
|
||||
Dictionary *const dict = Create<Dictionary>();
|
||||
|
||||
if (string.IsEmpty())
|
||||
{
|
||||
|
@ -2158,7 +2158,7 @@ Dictionary *DictionaryFromString(const FString &string)
|
|||
return dict;
|
||||
}
|
||||
|
||||
dict->Insert(i->name.GetString(), i->value.GetString());
|
||||
dict->Map.Insert(i->name.GetString(), i->value.GetString());
|
||||
}
|
||||
|
||||
return dict;
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
* unsigned int and 64-bit unsigned int in hexadecimal format.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifndef SFMT_H
|
||||
#define SFMT_H
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ EXTERN_CVAR (Float, snd_sfxvolume)
|
|||
EXTERN_CVAR (Float, snd_musicvolume)
|
||||
CVAR (Int, snd_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Int, snd_buffersize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Int, snd_hrtf, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Int, snd_hrtf, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
#if !defined(NO_OPENAL)
|
||||
#define DEF_BACKEND "openal"
|
||||
|
@ -127,15 +127,15 @@ public:
|
|||
void SetMusicVolume (float volume)
|
||||
{
|
||||
}
|
||||
std::pair<SoundHandle,bool> LoadSound(uint8_t *sfxdata, int length, bool monoize, FSoundLoadBuffer *pBuffer)
|
||||
SoundHandle LoadSound(uint8_t *sfxdata, int length)
|
||||
{
|
||||
SoundHandle retval = { NULL };
|
||||
return std::make_pair(retval, true);
|
||||
return retval;
|
||||
}
|
||||
std::pair<SoundHandle,bool> LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend, bool monoize)
|
||||
SoundHandle LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend)
|
||||
{
|
||||
SoundHandle retval = { NULL };
|
||||
return std::make_pair(retval, true);
|
||||
return retval;
|
||||
}
|
||||
void UnloadSound (SoundHandle sfx)
|
||||
{
|
||||
|
@ -171,17 +171,17 @@ public:
|
|||
}
|
||||
|
||||
// Starts a sound.
|
||||
FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan)
|
||||
FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan, float startTime)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
FISoundChannel *StartSound3D (SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan)
|
||||
FISoundChannel *StartSound3D (SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Marks a channel's start time without actually playing it.
|
||||
void MarkStartTime (FISoundChannel *chan)
|
||||
void MarkStartTime (FISoundChannel *chan, float startTime)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -339,7 +339,7 @@ FString SoundStream::GetStats()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
std::pair<SoundHandle,bool> SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int length, bool monoize)
|
||||
SoundHandle SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int length)
|
||||
{
|
||||
uint8_t * data = NULL;
|
||||
int len, frequency, channels, bits, loopstart, loopend;
|
||||
|
@ -370,7 +370,7 @@ std::pair<SoundHandle,bool> SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int le
|
|||
switch (blocktype)
|
||||
{
|
||||
case 1: // Sound data
|
||||
if (noextra && (codec == -1 || codec == sfxdata[i+1]))
|
||||
if (/*noextra &*/ (codec == -1 || codec == sfxdata[i + 1])) // NAM contains a VOC where a valid data block follows an extra block.
|
||||
{
|
||||
frequency = 1000000/(256 - sfxdata[i]);
|
||||
channels = 1;
|
||||
|
@ -382,6 +382,7 @@ std::pair<SoundHandle,bool> SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int le
|
|||
else okay = false;
|
||||
len += blocksize - 2;
|
||||
}
|
||||
else okay = false;
|
||||
break;
|
||||
case 2: // Sound data continuation
|
||||
if (codec == -1)
|
||||
|
@ -483,14 +484,7 @@ std::pair<SoundHandle,bool> SoundRenderer::LoadSoundVoc(uint8_t *sfxdata, int le
|
|||
}
|
||||
|
||||
} while (false);
|
||||
std::pair<SoundHandle,bool> retval = LoadSoundRaw(data, len, frequency, channels, bits, loopstart, loopend, monoize);
|
||||
SoundHandle retval = LoadSoundRaw(data, len, frequency, channels, bits, loopstart, loopend);
|
||||
if (data) delete[] data;
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::pair<SoundHandle, bool> SoundRenderer::LoadSoundBuffered(FSoundLoadBuffer *buffer, bool monoize)
|
||||
{
|
||||
SoundHandle retval = { NULL };
|
||||
return std::make_pair(retval, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -88,16 +88,6 @@ typedef bool (*SoundStreamCallback)(SoundStream *stream, void *buff, int len, vo
|
|||
struct SoundDecoder;
|
||||
class MIDIDevice;
|
||||
|
||||
struct FSoundLoadBuffer
|
||||
{
|
||||
std::vector<uint8_t> mBuffer;
|
||||
uint32_t loop_start;
|
||||
uint32_t loop_end;
|
||||
ChannelConfig chans;
|
||||
SampleType type;
|
||||
int srate;
|
||||
};
|
||||
|
||||
class SoundRenderer
|
||||
{
|
||||
public:
|
||||
|
@ -107,11 +97,9 @@ public:
|
|||
virtual bool IsNull() { return false; }
|
||||
virtual void SetSfxVolume (float volume) = 0;
|
||||
virtual void SetMusicVolume (float volume) = 0;
|
||||
// Returns a pair containing a sound handle and a boolean indicating the sound can be used in 3D.
|
||||
virtual std::pair<SoundHandle,bool> LoadSound(uint8_t *sfxdata, int length, bool monoize=false, FSoundLoadBuffer *pBuffer = nullptr) = 0;
|
||||
std::pair<SoundHandle,bool> LoadSoundVoc(uint8_t *sfxdata, int length, bool monoize=false);
|
||||
virtual std::pair<SoundHandle,bool> LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1, bool monoize = false) = 0;
|
||||
virtual std::pair<SoundHandle, bool> LoadSoundBuffered(FSoundLoadBuffer *buffer, bool monoize);
|
||||
virtual SoundHandle LoadSound(uint8_t *sfxdata, int length) = 0;
|
||||
SoundHandle LoadSoundVoc(uint8_t *sfxdata, int length);
|
||||
virtual SoundHandle LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1) = 0;
|
||||
virtual void UnloadSound (SoundHandle sfx) = 0; // unloads a sound from memory
|
||||
virtual unsigned int GetMSLength(SoundHandle sfx) = 0; // Gets the length of a sound at its default frequency
|
||||
virtual unsigned int GetSampleLength(SoundHandle sfx) = 0; // Gets the length of a sound at its default frequency
|
||||
|
@ -121,8 +109,8 @@ public:
|
|||
virtual SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) = 0;
|
||||
|
||||
// Starts a sound.
|
||||
virtual FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) = 0;
|
||||
virtual FISoundChannel *StartSound3D (SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan) = 0;
|
||||
virtual FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan, float startTime = 0.f) = 0;
|
||||
virtual FISoundChannel *StartSound3D (SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime = 0.f) = 0;
|
||||
|
||||
// Stops a sound channel.
|
||||
virtual void StopChannel (FISoundChannel *chan) = 0;
|
||||
|
@ -134,7 +122,7 @@ public:
|
|||
virtual void ChannelPitch(FISoundChannel *chan, float volume) = 0;
|
||||
|
||||
// Marks a channel's start time without actually playing it.
|
||||
virtual void MarkStartTime (FISoundChannel *chan) = 0;
|
||||
virtual void MarkStartTime (FISoundChannel *chan, float startTime = 0.f) = 0;
|
||||
|
||||
// Returns position of sound on this channel, in samples.
|
||||
virtual unsigned int GetPosition(FISoundChannel *chan) = 0;
|
||||
|
|
|
@ -53,7 +53,7 @@ FModule OpenALModule{"OpenAL"};
|
|||
#include "oalload.h"
|
||||
|
||||
CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (Bool, snd_efx, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CVAR (String, snd_alresampler, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -185,7 +185,7 @@ class OpenALSoundStream : public SoundStream
|
|||
if(Renderer->FreeSfx.Size() == 0)
|
||||
{
|
||||
FSoundChan *lowest = Renderer->FindLowestChannel();
|
||||
if(lowest) Renderer->ForceStopChannel(lowest);
|
||||
if(lowest) Renderer->StopChannel(lowest);
|
||||
|
||||
if(Renderer->FreeSfx.Size() == 0)
|
||||
return false;
|
||||
|
@ -667,14 +667,6 @@ OpenALSoundRenderer::OpenALSoundRenderer()
|
|||
return;
|
||||
}
|
||||
|
||||
ALCint refresh=0;
|
||||
alcGetIntegerv(Device, ALC_REFRESH, 1, &refresh);
|
||||
if(refresh > 0)
|
||||
{
|
||||
// Round up instead of down
|
||||
UpdateTimeMS = (1000+refresh-1) / refresh;
|
||||
}
|
||||
|
||||
ALCint numMono=0, numStereo=0;
|
||||
alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono);
|
||||
alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo);
|
||||
|
@ -985,14 +977,11 @@ float OpenALSoundRenderer::GetOutputRate()
|
|||
}
|
||||
|
||||
|
||||
std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend, bool monoize)
|
||||
SoundHandle OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend)
|
||||
{
|
||||
SoundHandle retval = { NULL };
|
||||
|
||||
if(length == 0) return std::make_pair(retval, true);
|
||||
|
||||
/* Only downmix to mono if we can't spatialize multi-channel sounds. */
|
||||
monoize = monoize && !AL.SOFT_source_spatialize;
|
||||
if(length == 0) return retval;
|
||||
|
||||
if(bits == -8)
|
||||
{
|
||||
|
@ -1002,33 +991,6 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata,
|
|||
bits = -bits;
|
||||
}
|
||||
|
||||
if(channels > 1 && monoize)
|
||||
{
|
||||
size_t frames = length / channels * 8 / bits;
|
||||
if(bits == 16)
|
||||
{
|
||||
for(size_t i = 0;i < frames;i++)
|
||||
{
|
||||
int sum = 0;
|
||||
for(int c = 0;c < channels;c++)
|
||||
sum += ((short*)sfxdata)[i*channels + c];
|
||||
((short*)sfxdata)[i] = sum / channels;
|
||||
}
|
||||
}
|
||||
else if(bits == 8)
|
||||
{
|
||||
for(size_t i = 0;i < frames;i++)
|
||||
{
|
||||
int sum = 0;
|
||||
for(int c = 0;c < channels;c++)
|
||||
sum += sfxdata[i*channels + c] - 128;
|
||||
sfxdata[i] = (sum / channels) + 128;
|
||||
}
|
||||
}
|
||||
length /= channels;
|
||||
channels = 1;
|
||||
}
|
||||
|
||||
ALenum format = AL_NONE;
|
||||
if(bits == 16)
|
||||
{
|
||||
|
@ -1044,7 +1006,7 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata,
|
|||
if(format == AL_NONE || frequency <= 0)
|
||||
{
|
||||
Printf("Unhandled format: %d bit, %d channel, %d hz\n", bits, channels, frequency);
|
||||
return std::make_pair(retval, true);
|
||||
return retval;
|
||||
}
|
||||
length -= length%(channels*bits/8);
|
||||
|
||||
|
@ -1057,7 +1019,7 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata,
|
|||
Printf("Failed to buffer data: %s\n", alGetString(err));
|
||||
alDeleteBuffers(1, &buffer);
|
||||
getALError();
|
||||
return std::make_pair(retval, true);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if((loopstart > 0 || loopend > 0) && AL.SOFT_loop_points)
|
||||
|
@ -1081,11 +1043,15 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata,
|
|||
}
|
||||
|
||||
retval.data = MAKE_PTRID(buffer);
|
||||
return std::make_pair(retval, AL.SOFT_source_spatialize || channels==1);
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, bool monoize, FSoundLoadBuffer *pBuffer)
|
||||
SoundHandle OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length)
|
||||
{
|
||||
#ifdef __MOBILE__ // 3D sounds are very loud without making the sound mono. This needs to be fixed because it is making all sounds mono for now..
|
||||
bool monoize = true;
|
||||
#endif
|
||||
|
||||
SoundHandle retval = { NULL };
|
||||
ALenum format = AL_NONE;
|
||||
ChannelConfig chans;
|
||||
|
@ -1094,19 +1060,18 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
uint32_t loop_start = 0, loop_end = ~0u;
|
||||
bool startass = false, endass = false;
|
||||
|
||||
/* Only downmix to mono if we can't spatialize multi-channel sounds. */
|
||||
monoize = monoize && !AL.SOFT_source_spatialize;
|
||||
|
||||
FindLoopTags(sfxdata, length, &loop_start, &startass, &loop_end, &endass);
|
||||
auto decoder = CreateDecoder(sfxdata, length, true);
|
||||
if (!decoder)
|
||||
{
|
||||
return std::make_pair(retval, true);
|
||||
}
|
||||
return retval;
|
||||
|
||||
SoundDecoder_GetInfo(decoder, &srate, &chans, &type);
|
||||
int samplesize = 1;
|
||||
#ifdef __MOBILE__
|
||||
if (chans == ChannelConfig_Mono || monoize)
|
||||
#else
|
||||
if (chans == ChannelConfig_Mono)
|
||||
#endif
|
||||
{
|
||||
if (type == SampleType_UInt8) format = AL_FORMAT_MONO8, samplesize = 1;
|
||||
if (type == SampleType_Int16) format = AL_FORMAT_MONO16, samplesize = 2;
|
||||
|
@ -1122,7 +1087,7 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
SoundDecoder_Close(decoder);
|
||||
Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans),
|
||||
GetSampleTypeName(type));
|
||||
return std::make_pair(retval, true);
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
|
@ -1138,6 +1103,7 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
data.resize(total);
|
||||
SoundDecoder_Close(decoder);
|
||||
|
||||
#ifdef __MOBILE__
|
||||
if(chans != ChannelConfig_Mono && monoize)
|
||||
{
|
||||
size_t chancount = GetChannelCount(chans);
|
||||
|
@ -1167,6 +1133,7 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
}
|
||||
data.resize((data.size()/chancount));
|
||||
}
|
||||
#endif
|
||||
|
||||
ALenum err;
|
||||
ALuint buffer = 0;
|
||||
|
@ -1177,7 +1144,7 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
Printf("Failed to buffer data: %s\n", alGetString(err));
|
||||
alDeleteBuffers(1, &buffer);
|
||||
getALError();
|
||||
return std::make_pair(retval, true);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!startass) loop_start = Scale(loop_start, srate, 1000);
|
||||
|
@ -1195,103 +1162,7 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
}
|
||||
|
||||
retval.data = MAKE_PTRID(buffer);
|
||||
if (pBuffer != nullptr)
|
||||
{
|
||||
pBuffer->mBuffer = std::move(data);
|
||||
pBuffer->loop_start = loop_start;
|
||||
pBuffer->loop_end = loop_end;
|
||||
pBuffer->chans = chans;
|
||||
pBuffer->type = type;
|
||||
pBuffer->srate = srate;
|
||||
}
|
||||
return std::make_pair(retval, AL.SOFT_source_spatialize || chans == ChannelConfig_Mono || monoize);
|
||||
}
|
||||
|
||||
std::pair<SoundHandle, bool> OpenALSoundRenderer::LoadSoundBuffered(FSoundLoadBuffer *pBuffer, bool monoize)
|
||||
{
|
||||
SoundHandle retval = { NULL };
|
||||
ALenum format = AL_NONE;
|
||||
int srate = pBuffer->srate;
|
||||
auto type = pBuffer->type;
|
||||
auto chans = pBuffer->chans;
|
||||
uint32_t loop_start = pBuffer->loop_start, loop_end = pBuffer->loop_end;
|
||||
|
||||
/* Only downmix to mono if we can't spatialize multi-channel sounds. */
|
||||
monoize = monoize && !AL.SOFT_source_spatialize;
|
||||
|
||||
if (chans == ChannelConfig_Mono || monoize)
|
||||
{
|
||||
if (type == SampleType_UInt8) format = AL_FORMAT_MONO8;
|
||||
if (type == SampleType_Int16) format = AL_FORMAT_MONO16;
|
||||
}
|
||||
else if (chans == ChannelConfig_Stereo)
|
||||
{
|
||||
if (type == SampleType_UInt8) format = AL_FORMAT_STEREO8;
|
||||
if (type == SampleType_Int16) format = AL_FORMAT_STEREO16;
|
||||
}
|
||||
|
||||
if (format == AL_NONE)
|
||||
{
|
||||
Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans),
|
||||
GetSampleTypeName(type));
|
||||
return std::make_pair(retval, true);
|
||||
}
|
||||
|
||||
auto &data = pBuffer->mBuffer;
|
||||
|
||||
if (pBuffer->chans == ChannelConfig_Stereo && monoize)
|
||||
{
|
||||
size_t chancount = GetChannelCount(chans);
|
||||
size_t frames = data.size() / chancount /
|
||||
(type == SampleType_Int16 ? 2 : 1);
|
||||
if (type == SampleType_Int16)
|
||||
{
|
||||
short *sfxdata = (short*)&data[0];
|
||||
for (size_t i = 0; i < frames; i++)
|
||||
{
|
||||
int sum = 0;
|
||||
for (size_t c = 0; c < chancount; c++)
|
||||
sum += sfxdata[i*chancount + c];
|
||||
sfxdata[i] = short(sum / chancount);
|
||||
}
|
||||
}
|
||||
else if (type == SampleType_UInt8)
|
||||
{
|
||||
uint8_t *sfxdata = (uint8_t*)&data[0];
|
||||
for (size_t i = 0; i < frames; i++)
|
||||
{
|
||||
int sum = 0;
|
||||
for (size_t c = 0; c < chancount; c++)
|
||||
sum += sfxdata[i*chancount + c] - 128;
|
||||
sfxdata[i] = uint8_t((sum / chancount) + 128);
|
||||
}
|
||||
}
|
||||
data.resize(data.size() / chancount);
|
||||
}
|
||||
|
||||
ALenum err;
|
||||
ALuint buffer = 0;
|
||||
alGenBuffers(1, &buffer);
|
||||
alBufferData(buffer, format, &data[0], (ALsizei)data.size(), srate);
|
||||
if ((err = getALError()) != AL_NO_ERROR)
|
||||
{
|
||||
Printf("Failed to buffer data: %s\n", alGetString(err));
|
||||
alDeleteBuffers(1, &buffer);
|
||||
getALError();
|
||||
return std::make_pair(retval, true);
|
||||
}
|
||||
|
||||
// the loop points were already validated by the previous load.
|
||||
if ((loop_start > 0 || loop_end > 0) && loop_end > loop_start && AL.SOFT_loop_points)
|
||||
{
|
||||
ALint loops[2] = { static_cast<ALint>(loop_start), static_cast<ALint>(loop_end) };
|
||||
DPrintf(DMSG_NOTIFY, "Setting loop points %d -> %d\n", loops[0], loops[1]);
|
||||
alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops);
|
||||
// no console messages here, please!
|
||||
}
|
||||
|
||||
retval.data = MAKE_PTRID(buffer);
|
||||
return std::make_pair(retval, AL.SOFT_source_spatialize || chans == ChannelConfig_Mono || monoize);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void OpenALSoundRenderer::UnloadSound(SoundHandle sfx)
|
||||
|
@ -1310,7 +1181,7 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx)
|
|||
if((ALuint)bufID == buffer)
|
||||
{
|
||||
FSoundChan *next = schan->NextChan;
|
||||
ForceStopChannel(schan);
|
||||
StopChannel(schan);
|
||||
schan = next;
|
||||
continue;
|
||||
}
|
||||
|
@ -1318,20 +1189,6 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx)
|
|||
schan = schan->NextChan;
|
||||
}
|
||||
|
||||
// Make sure to kill any currently fading sounds too
|
||||
for(auto iter = FadingSources.begin();iter != FadingSources.end();)
|
||||
{
|
||||
ALint bufID = 0;
|
||||
alGetSourcei(iter->first, AL_BUFFER, &bufID);
|
||||
if(static_cast<ALuint>(bufID) == buffer)
|
||||
{
|
||||
FreeSource(iter->first);
|
||||
iter = FadingSources.erase(iter);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
|
||||
alDeleteBuffers(1, &buffer);
|
||||
getALError();
|
||||
}
|
||||
|
@ -1350,12 +1207,12 @@ SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int
|
|||
return stream;
|
||||
}
|
||||
|
||||
FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan)
|
||||
FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan, float startTime)
|
||||
{
|
||||
if(FreeSfx.Size() == 0)
|
||||
{
|
||||
FSoundChan *lowest = FindLowestChannel();
|
||||
if(lowest) ForceStopChannel(lowest);
|
||||
if(lowest) StopChannel(lowest);
|
||||
|
||||
if(FreeSfx.Size() == 0)
|
||||
return NULL;
|
||||
|
@ -1401,7 +1258,10 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int
|
|||
alSourcef(source, AL_PITCH, PITCH(pitch));
|
||||
|
||||
if(!reuse_chan || reuse_chan->StartTime == 0)
|
||||
alSourcef(source, AL_SEC_OFFSET, 0.f);
|
||||
{
|
||||
float st = (chanflags&SNDF_LOOP) ? fmod(startTime, (float)GetMSLength(sfx) / 1000.f) : clamp<float>(startTime, 0.f, (float)GetMSLength(sfx) / 1000.f);
|
||||
alSourcef(source, AL_SEC_OFFSET, st);
|
||||
}
|
||||
else
|
||||
{
|
||||
if((chanflags&SNDF_ABSTIME))
|
||||
|
@ -1450,7 +1310,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int
|
|||
|
||||
FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *listener, float vol,
|
||||
FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel,
|
||||
int channum, int chanflags, FISoundChannel *reuse_chan)
|
||||
int channum, int chanflags, FISoundChannel *reuse_chan, float startTime)
|
||||
{
|
||||
float dist_sqr = (float)(pos - listener->position).LengthSquared();
|
||||
|
||||
|
@ -1461,7 +1321,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener
|
|||
{
|
||||
if(lowest->Priority < priority || (lowest->Priority == priority &&
|
||||
lowest->DistanceSqr > dist_sqr))
|
||||
ForceStopChannel(lowest);
|
||||
StopChannel(lowest);
|
||||
}
|
||||
if(FreeSfx.Size() == 0)
|
||||
return NULL;
|
||||
|
@ -1518,28 +1378,38 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener
|
|||
alSourcef(source, AL_MAX_DISTANCE, 100000.f);
|
||||
alSourcef(source, AL_ROLLOFF_FACTOR, 1.f);
|
||||
|
||||
FVector3 dir = pos - listener->position;
|
||||
if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f)))
|
||||
{
|
||||
float gain = GetRolloff(rolloff, sqrtf(dist_sqr) * distscale);
|
||||
dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f);
|
||||
}
|
||||
if(AL.EXT_SOURCE_RADIUS)
|
||||
{
|
||||
/* Since the OpenAL distance is decoupled from the sound's distance, get the OpenAL
|
||||
* distance that corresponds to the area radius. */
|
||||
float gain = GetRolloff(rolloff, AREA_SOUND_RADIUS);
|
||||
alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ?
|
||||
// Clamp in case the max distance is <= the area radius
|
||||
1.f/std::max<float>(GetRolloff(rolloff, AREA_SOUND_RADIUS), 0.00001f) : 0.f
|
||||
((gain > 0.00001f) ? 1.f/gain : 100000.f) : 0.f
|
||||
);
|
||||
}
|
||||
else if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS)
|
||||
|
||||
if(dist_sqr < (0.0004f*0.0004f))
|
||||
{
|
||||
FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f);
|
||||
float a = sqrtf(dist_sqr) / AREA_SOUND_RADIUS;
|
||||
dir = amb + (dir-amb)*a;
|
||||
// Head relative
|
||||
alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f);
|
||||
}
|
||||
dir += listener->position;
|
||||
else
|
||||
{
|
||||
float gain = GetRolloff(rolloff, sqrtf(dist_sqr) * distscale);
|
||||
FVector3 dir = pos - listener->position;
|
||||
dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f);
|
||||
dir += listener->position;
|
||||
|
||||
alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(AL.EXT_SOURCE_RADIUS)
|
||||
alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f);
|
||||
|
||||
if(dist_sqr < (0.0004f*0.0004f))
|
||||
{
|
||||
|
@ -1550,35 +1420,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener
|
|||
else
|
||||
{
|
||||
alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FVector3 dir = pos;
|
||||
if(AL.EXT_SOURCE_RADIUS)
|
||||
alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f);
|
||||
else if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS)
|
||||
{
|
||||
dir -= listener->position;
|
||||
|
||||
float mindist = rolloff->MinDistance/distscale;
|
||||
FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f);
|
||||
float a = sqrtf(dist_sqr) / AREA_SOUND_RADIUS;
|
||||
dir = amb + (dir-amb)*a;
|
||||
|
||||
dir += listener->position;
|
||||
}
|
||||
if(dist_sqr < (0.0004f*0.0004f))
|
||||
{
|
||||
// Head relative
|
||||
alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]);
|
||||
alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]);
|
||||
}
|
||||
}
|
||||
alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]);
|
||||
|
@ -1612,7 +1454,13 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener
|
|||
alSourcef(source, AL_PITCH, PITCH(pitch));
|
||||
|
||||
if(!reuse_chan || reuse_chan->StartTime == 0)
|
||||
alSourcef(source, AL_SEC_OFFSET, 0.f);
|
||||
{
|
||||
float sfxlength = (float)GetMSLength(sfx) / 1000.f;
|
||||
float st = (chanflags & SNDF_LOOP)
|
||||
? (sfxlength > 0 ? fmod(startTime, sfxlength) : 0)
|
||||
: clamp<float>(startTime, 0.f, sfxlength);
|
||||
alSourcef(source, AL_SEC_OFFSET, st);
|
||||
}
|
||||
else
|
||||
{
|
||||
if((chanflags&SNDF_ABSTIME))
|
||||
|
@ -1682,8 +1530,15 @@ void OpenALSoundRenderer::ChannelPitch(FISoundChannel *chan, float pitch)
|
|||
alSourcef(source, AL_PITCH, std::max(pitch, 0.0001f));
|
||||
}
|
||||
|
||||
void OpenALSoundRenderer::FreeSource(ALuint source)
|
||||
void OpenALSoundRenderer::StopChannel(FISoundChannel *chan)
|
||||
{
|
||||
if(chan == NULL || chan->SysChannel == NULL)
|
||||
return;
|
||||
|
||||
ALuint source = GET_PTRID(chan->SysChannel);
|
||||
// Release first, so it can be properly marked as evicted if it's being killed
|
||||
soundEngine->ChannelEnded(chan);
|
||||
|
||||
alSourceRewind(source);
|
||||
alSourcei(source, AL_BUFFER, 0);
|
||||
getALError();
|
||||
|
@ -1699,41 +1554,6 @@ void OpenALSoundRenderer::FreeSource(ALuint source)
|
|||
FreeSfx.Push(source);
|
||||
}
|
||||
|
||||
void OpenALSoundRenderer::StopChannel(FISoundChannel *chan)
|
||||
{
|
||||
if(chan == NULL || chan->SysChannel == NULL)
|
||||
return;
|
||||
|
||||
ALuint source = GET_PTRID(chan->SysChannel);
|
||||
// Release first, so it can be properly marked as evicted if it's being killed
|
||||
soundEngine->ChannelEnded(chan);
|
||||
|
||||
ALint state = AL_INITIAL;
|
||||
alGetSourcei(source, AL_SOURCE_STATE, &state);
|
||||
if(state != AL_PLAYING)
|
||||
FreeSource(source);
|
||||
else
|
||||
{
|
||||
// The sound is being killed while playing, so set its gain to 0 and track it
|
||||
// as it fades.
|
||||
alSourcef(source, AL_GAIN, 0.f);
|
||||
getALError();
|
||||
|
||||
FadingSources.insert(std::make_pair(
|
||||
source, std::chrono::steady_clock::now().time_since_epoch().count()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void OpenALSoundRenderer::ForceStopChannel(FISoundChannel *chan)
|
||||
{
|
||||
ALuint source = GET_PTRID(chan->SysChannel);
|
||||
if(!source) return;
|
||||
|
||||
soundEngine->ChannelEnded(chan);
|
||||
FreeSource(source);
|
||||
}
|
||||
|
||||
|
||||
unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan)
|
||||
{
|
||||
|
@ -1772,9 +1592,11 @@ void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
extern "C" void OpenSL_android_set_pause( ALCdevice_struct *Device, int pause );
|
||||
#endif
|
||||
|
||||
void OpenALSoundRenderer::SetInactive(SoundRenderer::EInactiveState state)
|
||||
{
|
||||
switch(state)
|
||||
|
@ -1850,43 +1672,26 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh
|
|||
return;
|
||||
|
||||
FVector3 dir = pos - listener->position;
|
||||
chan->DistanceSqr = (float)dir.LengthSquared();
|
||||
|
||||
if(chan->ManualRolloff)
|
||||
{
|
||||
if(!AL.EXT_SOURCE_RADIUS && areasound &&
|
||||
chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS)
|
||||
{
|
||||
FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f);
|
||||
float a = sqrtf(chan->DistanceSqr) / AREA_SOUND_RADIUS;
|
||||
dir = amb + (dir-amb)*a;
|
||||
}
|
||||
if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f)))
|
||||
{
|
||||
float gain = GetRolloff(&chan->Rolloff, sqrtf(chan->DistanceSqr)*chan->DistanceScale);
|
||||
dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f);
|
||||
}
|
||||
}
|
||||
else if(!AL.EXT_SOURCE_RADIUS && areasound &&
|
||||
chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS)
|
||||
{
|
||||
float mindist = chan->Rolloff.MinDistance / chan->DistanceScale;
|
||||
FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f);
|
||||
float a = sqrtf(chan->DistanceSqr) / AREA_SOUND_RADIUS;
|
||||
dir = amb + (dir-amb)*a;
|
||||
}
|
||||
dir += listener->position;
|
||||
float dist_sqr = (float)dir.LengthSquared();
|
||||
chan->DistanceSqr = dist_sqr;
|
||||
|
||||
alDeferUpdatesSOFT();
|
||||
ALuint source = GET_PTRID(chan->SysChannel);
|
||||
|
||||
if(chan->DistanceSqr < (0.0004f*0.0004f))
|
||||
if(dist_sqr < (0.0004f*0.0004f))
|
||||
{
|
||||
alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
|
||||
alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(chan->ManualRolloff)
|
||||
{
|
||||
float gain = GetRolloff(&chan->Rolloff, sqrtf(dist_sqr)*chan->DistanceScale);
|
||||
dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f);
|
||||
}
|
||||
dir += listener->position;
|
||||
|
||||
alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
|
||||
alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]);
|
||||
}
|
||||
|
@ -2025,23 +1830,6 @@ void OpenALSoundRenderer::UpdateSounds()
|
|||
{
|
||||
alProcessUpdatesSOFT();
|
||||
|
||||
if(!FadingSources.empty())
|
||||
{
|
||||
auto cur_time = std::chrono::steady_clock::now().time_since_epoch();
|
||||
for(auto iter = FadingSources.begin();iter != FadingSources.end();)
|
||||
{
|
||||
auto time_diff = std::chrono::duration_cast<std::chrono::milliseconds>(cur_time -
|
||||
std::chrono::steady_clock::time_point::duration(iter->second));
|
||||
if(time_diff.count() >= UpdateTimeMS)
|
||||
{
|
||||
FreeSource(iter->first);
|
||||
iter = FadingSources.erase(iter);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
if(ALC.EXT_disconnect)
|
||||
{
|
||||
ALCint connected = ALC_TRUE;
|
||||
|
@ -2062,11 +1850,14 @@ bool OpenALSoundRenderer::IsValid()
|
|||
return Device != NULL;
|
||||
}
|
||||
|
||||
void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan)
|
||||
void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan, float startTime)
|
||||
{
|
||||
// FIXME: Get current time (preferably from the audio clock, but the system
|
||||
// time will have to do)
|
||||
chan->StartTime = std::chrono::steady_clock::now().time_since_epoch().count();
|
||||
using namespace std::chrono;
|
||||
auto startTimeDuration = duration<double>(startTime);
|
||||
auto diff = steady_clock::now().time_since_epoch() - startTimeDuration;
|
||||
chan->StartTime = static_cast<uint64_t>(duration_cast<nanoseconds>(diff).count());
|
||||
}
|
||||
|
||||
float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan)
|
||||
|
@ -2190,7 +1981,7 @@ void OpenALSoundRenderer::PurgeStoppedSources()
|
|||
{
|
||||
if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel))
|
||||
{
|
||||
ForceStopChannel(schan);
|
||||
StopChannel(schan);
|
||||
break;
|
||||
}
|
||||
schan = schan->NextChan;
|
||||
|
|
|
@ -125,9 +125,8 @@ public:
|
|||
|
||||
virtual void SetSfxVolume(float volume);
|
||||
virtual void SetMusicVolume(float volume);
|
||||
virtual std::pair<SoundHandle, bool> LoadSound(uint8_t *sfxdata, int length, bool monoize, FSoundLoadBuffer *buffer);
|
||||
virtual std::pair<SoundHandle,bool> LoadSoundBuffered(FSoundLoadBuffer *buffer, bool monoize);
|
||||
virtual std::pair<SoundHandle,bool> LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1, bool monoize = false);
|
||||
virtual SoundHandle LoadSound(uint8_t *sfxdata, int length);
|
||||
virtual SoundHandle LoadSoundRaw(uint8_t *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1);
|
||||
virtual void UnloadSound(SoundHandle sfx);
|
||||
virtual unsigned int GetMSLength(SoundHandle sfx);
|
||||
virtual unsigned int GetSampleLength(SoundHandle sfx);
|
||||
|
@ -137,8 +136,8 @@ public:
|
|||
virtual SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata);
|
||||
|
||||
// Starts a sound.
|
||||
virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan);
|
||||
virtual FISoundChannel *StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan);
|
||||
virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan, float startTime);
|
||||
virtual FISoundChannel *StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan, float startTime);
|
||||
|
||||
// Changes a channel's volume.
|
||||
virtual void ChannelVolume(FISoundChannel *chan, float volume);
|
||||
|
@ -167,7 +166,7 @@ public:
|
|||
virtual void UpdateListener(SoundListener *);
|
||||
virtual void UpdateSounds();
|
||||
|
||||
virtual void MarkStartTime(FISoundChannel*);
|
||||
virtual void MarkStartTime(FISoundChannel*, float startTime);
|
||||
virtual float GetAudibility(FISoundChannel*);
|
||||
|
||||
|
||||
|
@ -245,10 +244,8 @@ private:
|
|||
void RemoveStream(OpenALSoundStream *stream);
|
||||
|
||||
void LoadReverb(const ReverbContainer *env);
|
||||
void FreeSource(ALuint source);
|
||||
void PurgeStoppedSources();
|
||||
static FSoundChan *FindLowestChannel();
|
||||
void ForceStopChannel(FISoundChannel *chan);
|
||||
|
||||
std::thread StreamThread;
|
||||
std::mutex StreamLock;
|
||||
|
@ -269,10 +266,6 @@ private:
|
|||
TArray<ALuint> ReverbSfx;
|
||||
TArray<ALuint> SfxGroup;
|
||||
|
||||
int UpdateTimeMS;
|
||||
using SourceTimeMap = std::unordered_map<ALuint,int64_t>;
|
||||
SourceTimeMap FadingSources;
|
||||
|
||||
const ReverbContainer *PrevEnvironment;
|
||||
|
||||
typedef TMap<uint16_t,ALuint> EffectMap;
|
||||
|
|
|
@ -235,7 +235,7 @@ static void SetupGenMidi()
|
|||
auto lump = Wads.CheckNumForName("GENMIDI", ns_global);
|
||||
if (lump < 0)
|
||||
{
|
||||
Printf("No GENMIDI lump found. OPL playback not available.");
|
||||
Printf("No GENMIDI lump found. OPL playback not available.\n");
|
||||
return;
|
||||
}
|
||||
auto data = Wads.OpenLumpReader(lump);
|
||||
|
|
|
@ -412,7 +412,7 @@ unsigned int S_GetMSLength(FSoundID sound)
|
|||
}
|
||||
}
|
||||
|
||||
sfx = soundEngine->LoadSound(sfx, nullptr);
|
||||
sfx = soundEngine->LoadSound(sfx);
|
||||
if (sfx != NULL) return GSnd->GetMSLength(sfx->data);
|
||||
else return 0;
|
||||
}
|
||||
|
|
|
@ -275,7 +275,7 @@ void S_InitData()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void S_SoundPitch(int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation, float pitch)
|
||||
void S_SoundPitch(int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation, float pitch, float startTime)
|
||||
{
|
||||
soundEngine->StartSound(SOURCE_None, nullptr, nullptr, channel, flags, sound_id, volume, attenuation, 0, pitch);
|
||||
}
|
||||
|
@ -293,7 +293,8 @@ DEFINE_ACTION_FUNCTION(DObject, S_Sound)
|
|||
PARAM_FLOAT(volume);
|
||||
PARAM_FLOAT(attn);
|
||||
PARAM_FLOAT(pitch);
|
||||
S_SoundPitch(channel & 7, EChanFlags::FromInt(channel & ~7), id, static_cast<float>(volume), static_cast<float>(attn), static_cast<float>(pitch));
|
||||
PARAM_FLOAT(startTime);
|
||||
S_SoundPitch(channel & 7, EChanFlags::FromInt(channel & ~7), id, static_cast<float>(volume), static_cast<float>(attn), static_cast<float>(pitch), static_cast<float>(startTime));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -306,7 +307,8 @@ DEFINE_ACTION_FUNCTION(DObject, S_StartSound)
|
|||
PARAM_FLOAT(volume);
|
||||
PARAM_FLOAT(attn);
|
||||
PARAM_FLOAT(pitch);
|
||||
S_SoundPitch(channel, EChanFlags::FromInt(flags), id, static_cast<float>(volume), static_cast<float>(attn), static_cast<float>(pitch));
|
||||
PARAM_FLOAT(startTime);
|
||||
S_SoundPitch(channel, EChanFlags::FromInt(flags), id, static_cast<float>(volume), static_cast<float>(attn), static_cast<float>(pitch), static_cast<float>(startTime));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -362,10 +364,10 @@ static bool VerifyActorSound(AActor* ent, FSoundID& sound_id, int& channel, ECha
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void S_SoundPitchActor(AActor *ent, int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation, float pitch)
|
||||
void S_SoundPitchActor(AActor *ent, int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation, float pitch, float startTime)
|
||||
{
|
||||
if (VerifyActorSound(ent, sound_id, channel, flags))
|
||||
soundEngine->StartSound (SOURCE_Actor, ent, nullptr, channel, flags, sound_id, volume, attenuation, 0, pitch);
|
||||
soundEngine->StartSound (SOURCE_Actor, ent, nullptr, channel, flags, sound_id, volume, attenuation, 0, pitch, startTime);
|
||||
}
|
||||
|
||||
void S_Sound(AActor *ent, int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation)
|
||||
|
@ -437,7 +439,7 @@ void S_Sound (const sector_t *sec, int channel, EChanFlags flags, FSoundID sfxid
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void S_PlaySoundPitch(AActor *a, int chan, EChanFlags flags, FSoundID sid, float vol, float atten, float pitch)
|
||||
void S_PlaySoundPitch(AActor *a, int chan, EChanFlags flags, FSoundID sid, float vol, float atten, float pitch, float startTime = 0.f)
|
||||
{
|
||||
if (a == nullptr || a->Sector->Flags & SECF_SILENT)
|
||||
return;
|
||||
|
@ -446,7 +448,7 @@ void S_PlaySoundPitch(AActor *a, int chan, EChanFlags flags, FSoundID sid, float
|
|||
{
|
||||
if (!(flags & CHANF_NOSTOP) || !S_IsActorPlayingSomething(a, chan, sid))
|
||||
{
|
||||
S_SoundPitchActor(a, chan, flags, sid, vol, atten, pitch);
|
||||
S_SoundPitchActor(a, chan, flags, sid, vol, atten, pitch, startTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -455,7 +457,7 @@ void S_PlaySoundPitch(AActor *a, int chan, EChanFlags flags, FSoundID sid, float
|
|||
{
|
||||
if (!(flags & CHANF_NOSTOP) || !soundEngine->IsSourcePlayingSomething(SOURCE_None, nullptr, chan, sid))
|
||||
{
|
||||
S_SoundPitch(chan, flags, sid, vol, ATTN_NONE, pitch);
|
||||
S_SoundPitch(chan, flags, sid, vol, ATTN_NONE, pitch, startTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -463,19 +465,19 @@ void S_PlaySoundPitch(AActor *a, int chan, EChanFlags flags, FSoundID sid, float
|
|||
|
||||
void S_PlaySound(AActor *a, int chan, EChanFlags flags, FSoundID sid, float vol, float atten)
|
||||
{
|
||||
S_PlaySoundPitch(a, chan, flags, sid, vol, atten, 0.f);
|
||||
S_PlaySoundPitch(a, chan, flags, sid, vol, atten, 0.f, 0.f);
|
||||
}
|
||||
|
||||
void A_StartSound(AActor *self, int soundid, int channel, int flags, double volume, double attenuation, double pitch)
|
||||
void A_StartSound(AActor *self, int soundid, int channel, int flags, double volume, double attenuation, double pitch, double startTime)
|
||||
{
|
||||
S_PlaySoundPitch(self, channel, EChanFlags::FromInt(flags), soundid, (float)volume, (float)attenuation, (float)pitch);
|
||||
S_PlaySoundPitch(self, channel, EChanFlags::FromInt(flags), soundid, (float)volume, (float)attenuation, (float)pitch, (float)startTime);
|
||||
}
|
||||
|
||||
void A_PlaySound(AActor* self, int soundid, int channel, double volume, int looping, double attenuation, int local, double pitch)
|
||||
{
|
||||
if (looping) channel |= CHANF_LOOP | CHANF_NOSTOP;
|
||||
if (local) channel |= CHANF_LOCAL;
|
||||
A_StartSound(self, soundid, channel & 7, channel & ~7, volume, attenuation, pitch);
|
||||
A_StartSound(self, soundid, channel & 7, channel & ~7, volume, attenuation, pitch, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
|
@ -492,6 +494,18 @@ void S_StopSound (AActor *actor, int channel)
|
|||
soundEngine->StopSound(SOURCE_Actor, actor, (i_compatflags & COMPATF_MAGICSILENCE) ? -1 : channel);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// S_StopAllActorSounds
|
||||
//
|
||||
// Stops all sounds on an actor.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void S_StopActorSounds(AActor *actor, int chanmin, int chanmax)
|
||||
{
|
||||
soundEngine->StopActorSounds(SOURCE_Actor, actor, chanmin, chanmax);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -16,7 +16,7 @@ void S_PrecacheLevel();
|
|||
|
||||
// Start sound for thing at <ent>
|
||||
void S_Sound(int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation);
|
||||
void S_SoundPitch(int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation, float pitch);
|
||||
void S_SoundPitch(int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation, float pitch, float startTime = 0.f);
|
||||
|
||||
|
||||
void S_Sound (AActor *ent, int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation);
|
||||
|
@ -25,7 +25,7 @@ void S_Sound (const FPolyObj *poly, int channel, EChanFlags flags, FSoundID sfxi
|
|||
void S_Sound (const sector_t *sec, int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation);
|
||||
void S_Sound (const DVector3 &pos, int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation);
|
||||
|
||||
void S_SoundPitchActor (AActor *ent, int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation, float pitch);
|
||||
void S_SoundPitchActor (AActor *ent, int channel, EChanFlags flags, FSoundID sfxid, float volume, float attenuation, float pitch, float startTime = 0.f);
|
||||
|
||||
// [Nash] Used by ACS and DECORATE
|
||||
void S_PlaySound(AActor *a, int chan, EChanFlags flags, FSoundID sid, float vol, float atten);
|
||||
|
@ -34,6 +34,7 @@ void S_PlaySound(AActor *a, int chan, EChanFlags flags, FSoundID sid, float vol,
|
|||
void S_StopSound (AActor *ent, int channel);
|
||||
void S_StopSound (const sector_t *sec, int channel);
|
||||
void S_StopSound (const FPolyObj *poly, int channel);
|
||||
void S_StopActorSounds(AActor *actor, int chanmin, int chanmax);
|
||||
|
||||
// Moves all sounds from one mobj to another
|
||||
void S_RelinkSound (AActor *from, AActor *to);
|
||||
|
@ -55,7 +56,7 @@ void S_ChangeActorSoundPitch(AActor *actor, int channel, double pitch);
|
|||
void S_SerializeSounds(FSerializer &arc);
|
||||
|
||||
void A_PlaySound(AActor *self, int soundid, int channel, double volume, int looping, double attenuation, int local, double pitch);
|
||||
void A_StartSound(AActor* self, int soundid, int channel, int flags, double volume, double attenuation, double pitch);
|
||||
void A_StartSound(AActor* self, int soundid, int channel, int flags, double volume, double attenuation, double pitch, double startTime = 0.);
|
||||
static void S_SetListener(AActor *listenactor);
|
||||
void S_SoundReset();
|
||||
void S_ResumeSound(bool state);
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdexcept>
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include "musicformats/win32/i_cd.h"
|
||||
|
|
|
@ -38,7 +38,9 @@
|
|||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "templates.h"
|
||||
#include "s_soundinternal.h"
|
||||
#include "m_swap.h"
|
||||
#include "superfasthash.h"
|
||||
|
@ -171,10 +173,7 @@ void SoundEngine::CacheSound (sfxinfo_t *sfx)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Since we do not know in what format the sound will be used, we have to cache both.
|
||||
FSoundLoadBuffer SoundBuffer;
|
||||
LoadSound(sfx, &SoundBuffer);
|
||||
LoadSound3D(sfx, &SoundBuffer);
|
||||
LoadSound(sfx);
|
||||
sfx->bUsed = true;
|
||||
}
|
||||
}
|
||||
|
@ -188,12 +187,9 @@ void SoundEngine::CacheSound (sfxinfo_t *sfx)
|
|||
|
||||
void SoundEngine::UnloadSound (sfxinfo_t *sfx)
|
||||
{
|
||||
if (sfx->data3d.isValid() && sfx->data != sfx->data3d)
|
||||
GSnd->UnloadSound(sfx->data3d);
|
||||
if (sfx->data.isValid())
|
||||
GSnd->UnloadSound(sfx->data);
|
||||
sfx->data.Clear();
|
||||
sfx->data3d.Clear();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -369,7 +365,7 @@ FSoundID SoundEngine::ResolveSound(const void *, int, FSoundID soundid, float &a
|
|||
//
|
||||
// S_StartSound
|
||||
//
|
||||
// 0 attenuation means full volume over whole primaryLevel->
|
||||
// 0 attenuation means full volume over whole level.
|
||||
// 0 < attenuation means to scale the distance by that amount when
|
||||
// calculating volume.
|
||||
//
|
||||
|
@ -377,7 +373,7 @@ FSoundID SoundEngine::ResolveSound(const void *, int, FSoundID soundid, float &a
|
|||
|
||||
FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
||||
const FVector3 *pt, int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation,
|
||||
FRolloffInfo *forcedrolloff, float spitch)
|
||||
FRolloffInfo *forcedrolloff, float spitch, float startTime)
|
||||
{
|
||||
sfxinfo_t *sfx;
|
||||
EChanFlags chanflags = flags;
|
||||
|
@ -387,9 +383,8 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
FSoundChan *chan;
|
||||
FVector3 pos, vel;
|
||||
FRolloffInfo *rolloff;
|
||||
FSoundLoadBuffer SoundBuffer;
|
||||
|
||||
if (sound_id <= 0 || volume <= 0 || nosfx || nosound )
|
||||
if (sound_id <= 0 || volume <= 0 || nosfx || nosound || blockNewSounds)
|
||||
return NULL;
|
||||
|
||||
// prevent crashes.
|
||||
|
@ -485,7 +480,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
}
|
||||
|
||||
// Make sure the sound is loaded.
|
||||
sfx = LoadSound(sfx, &SoundBuffer);
|
||||
sfx = LoadSound(sfx);
|
||||
|
||||
// The empty sound never plays.
|
||||
if (sfx->lumpnum == sfx_empty)
|
||||
|
@ -506,26 +501,9 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
int seen = 0;
|
||||
if (source != NULL && channel == CHAN_AUTO)
|
||||
{
|
||||
// Select a channel that isn't already playing something.
|
||||
// Try channel 0 first, then travel from channel 7 down.
|
||||
if (!IsChannelUsed(type, source, 0, &seen))
|
||||
{
|
||||
channel = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (channel = 7; channel > 0; --channel)
|
||||
{
|
||||
if (!IsChannelUsed(type, source, channel, &seen))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (channel == 0)
|
||||
{ // Crap. No free channels.
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// In the old sound system, 'AUTO' hijacked one of the other channels.
|
||||
// Now, with CHANF_OVERLAP at our disposal that isn't needed anymore. Just set the flag and let all sounds play on channel 0.
|
||||
chanflags |= CHANF_OVERLAP;
|
||||
}
|
||||
|
||||
// If this actor is already playing something on the selected channel, stop it.
|
||||
|
@ -576,14 +554,18 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source,
|
|||
if (chanflags & (CHANF_UI|CHANF_NOPAUSE)) startflags |= SNDF_NOPAUSE;
|
||||
if (chanflags & CHANF_UI) startflags |= SNDF_NOREVERB;
|
||||
|
||||
float sfxlength = (float)GSnd->GetMSLength(sfx->data) / 1000.f;
|
||||
startTime = (startflags & SNDF_LOOP)
|
||||
? (sfxlength > 0 ? fmod(startTime, sfxlength) : 0)
|
||||
: clamp<float>(startTime, 0.f, sfxlength);
|
||||
|
||||
if (attenuation > 0 && type != SOURCE_None)
|
||||
{
|
||||
LoadSound3D(sfx, &SoundBuffer);
|
||||
chan = (FSoundChan*)GSnd->StartSound3D (sfx->data3d, &listener, float(volume), rolloff, float(attenuation), pitch, basepriority, pos, vel, channel, startflags, NULL);
|
||||
chan = (FSoundChan*)GSnd->StartSound3D (sfx->data, &listener, float(volume), rolloff, float(attenuation), pitch, basepriority, pos, vel, channel, startflags, NULL, startTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
chan = (FSoundChan*)GSnd->StartSound (sfx->data, float(volume), pitch, startflags, NULL);
|
||||
chan = (FSoundChan*)GSnd->StartSound (sfx->data, float(volume), pitch, startflags, NULL, startTime);
|
||||
}
|
||||
}
|
||||
if (chan == NULL && (chanflags & CHANF_LOOP))
|
||||
|
@ -643,13 +625,12 @@ void SoundEngine::RestartChannel(FSoundChan *chan)
|
|||
|
||||
FSoundChan *ochan;
|
||||
sfxinfo_t *sfx = &S_sfx[chan->SoundID];
|
||||
FSoundLoadBuffer SoundBuffer;
|
||||
|
||||
// If this is a singular sound, don't play it if it's already playing.
|
||||
if (sfx->bSingular && CheckSingular(chan->SoundID))
|
||||
return;
|
||||
|
||||
sfx = LoadSound(sfx, &SoundBuffer);
|
||||
sfx = LoadSound(sfx);
|
||||
|
||||
// The empty sound never plays.
|
||||
if (sfx->lumpnum == sfx_empty)
|
||||
|
@ -683,9 +664,8 @@ void SoundEngine::RestartChannel(FSoundChan *chan)
|
|||
return;
|
||||
}
|
||||
|
||||
LoadSound3D(sfx, &SoundBuffer);
|
||||
chan->ChanFlags &= ~(CHANF_EVICTED|CHANF_ABSTIME);
|
||||
ochan = (FSoundChan*)GSnd->StartSound3D(sfx->data3d, &listener, chan->Volume, &chan->Rolloff, chan->DistanceScale, chan->Pitch,
|
||||
ochan = (FSoundChan*)GSnd->StartSound3D(sfx->data, &listener, chan->Volume, &chan->Rolloff, chan->DistanceScale, chan->Pitch,
|
||||
chan->Priority, pos, vel, chan->EntChannel, startflags, chan);
|
||||
}
|
||||
else
|
||||
|
@ -708,7 +688,7 @@ void SoundEngine::RestartChannel(FSoundChan *chan)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
sfxinfo_t *SoundEngine::LoadSound(sfxinfo_t *sfx, FSoundLoadBuffer *pBuffer)
|
||||
sfxinfo_t *SoundEngine::LoadSound(sfxinfo_t *sfx)
|
||||
{
|
||||
if (GSnd->IsNull()) return sfx;
|
||||
|
||||
|
@ -745,34 +725,29 @@ sfxinfo_t *SoundEngine::LoadSound(sfxinfo_t *sfx, FSoundLoadBuffer *pBuffer)
|
|||
if (size > 8)
|
||||
{
|
||||
int32_t dmxlen = LittleLong(((int32_t *)sfxdata.Data())[1]);
|
||||
std::pair<SoundHandle,bool> snd;
|
||||
|
||||
// If the sound is voc, use the custom loader.
|
||||
if (strncmp ((const char *)sfxdata.Data(), "Creative Voice File", 19) == 0)
|
||||
{
|
||||
snd = GSnd->LoadSoundVoc(sfxdata.Data(), size);
|
||||
sfx->data = GSnd->LoadSoundVoc(sfxdata.Data(), size);
|
||||
}
|
||||
// If the sound is raw, just load it as such.
|
||||
else if (sfx->bLoadRAW)
|
||||
{
|
||||
snd = GSnd->LoadSoundRaw(sfxdata.Data(), size, sfx->RawRate, 1, 8, sfx->LoopStart);
|
||||
sfx->data = GSnd->LoadSoundRaw(sfxdata.Data(), size, sfx->RawRate, 1, 8, sfx->LoopStart);
|
||||
}
|
||||
// Otherwise, try the sound as DMX format.
|
||||
else if (((uint8_t *)sfxdata.Data())[0] == 3 && ((uint8_t *)sfxdata.Data())[1] == 0 && dmxlen <= size - 8)
|
||||
{
|
||||
int frequency = LittleShort(((uint16_t *)sfxdata.Data())[1]);
|
||||
if (frequency == 0) frequency = 11025;
|
||||
snd = GSnd->LoadSoundRaw(sfxdata.Data()+8, dmxlen, frequency, 1, 8, sfx->LoopStart);
|
||||
sfx->data = GSnd->LoadSoundRaw(sfxdata.Data()+8, dmxlen, frequency, 1, 8, sfx->LoopStart);
|
||||
}
|
||||
// If that fails, let the sound system try and figure it out.
|
||||
else
|
||||
{
|
||||
snd = GSnd->LoadSound(sfxdata.Data(), size, false, pBuffer);
|
||||
sfx->data = GSnd->LoadSound(sfxdata.Data(), size);
|
||||
}
|
||||
|
||||
sfx->data = snd.first;
|
||||
if(snd.second)
|
||||
sfx->data3d = sfx->data;
|
||||
}
|
||||
|
||||
if (!sfx->data.isValid())
|
||||
|
@ -788,55 +763,6 @@ sfxinfo_t *SoundEngine::LoadSound(sfxinfo_t *sfx, FSoundLoadBuffer *pBuffer)
|
|||
return sfx;
|
||||
}
|
||||
|
||||
void SoundEngine::LoadSound3D(sfxinfo_t *sfx, FSoundLoadBuffer *pBuffer)
|
||||
{
|
||||
if (GSnd->IsNull()) return;
|
||||
|
||||
if(sfx->data3d.isValid())
|
||||
return;
|
||||
|
||||
//DPrintf(DMSG_NOTIFY, "Loading monoized sound \"%s\" (%td)\n", sfx->name.GetChars(), sfx - &S_sfx[0]);
|
||||
|
||||
std::pair<SoundHandle, bool> snd;
|
||||
|
||||
if (pBuffer->mBuffer.size() > 0)
|
||||
{
|
||||
snd = GSnd->LoadSoundBuffered(pBuffer, true);
|
||||
}
|
||||
else if (sfx->lumpnum >= 0)
|
||||
{
|
||||
auto sfxdata = ReadSound(sfx->lumpnum);
|
||||
int size = sfxdata.Size();
|
||||
if (size <= 8) return;
|
||||
int32_t dmxlen = LittleLong(((int32_t *)sfxdata.Data())[1]);
|
||||
|
||||
// If the sound is voc, use the custom loader.
|
||||
if (strncmp((const char *)sfxdata.Data(), "Creative Voice File", 19) == 0)
|
||||
{
|
||||
snd = GSnd->LoadSoundVoc(sfxdata.Data(), size, true);
|
||||
}
|
||||
// If the sound is raw, just load it as such.
|
||||
else if (sfx->bLoadRAW)
|
||||
{
|
||||
snd = GSnd->LoadSoundRaw(sfxdata.Data(), size, sfx->RawRate, 1, 8, sfx->LoopStart, true);
|
||||
}
|
||||
// Otherwise, try the sound as DMX format.
|
||||
else if (((uint8_t *)sfxdata.Data())[0] == 3 && ((uint8_t *)sfxdata.Data())[1] == 0 && dmxlen <= size - 8)
|
||||
{
|
||||
int frequency = LittleShort(((uint16_t *)sfxdata.Data())[1]);
|
||||
if (frequency == 0) frequency = 11025;
|
||||
snd = GSnd->LoadSoundRaw(sfxdata.Data() + 8, dmxlen, frequency, 1, 8, sfx->LoopStart, -1, true);
|
||||
}
|
||||
// If that fails, let the sound system try and figure it out.
|
||||
else
|
||||
{
|
||||
snd = GSnd->LoadSound(sfxdata.Data(), size, true, pBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
sfx->data3d = snd.first;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// S_CheckSingular
|
||||
|
@ -970,6 +896,38 @@ void SoundEngine::StopSound(int sourcetype, const void* actor, int channel, int
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// S_StopAllActorSounds
|
||||
//
|
||||
// Stops all sounds on an actor.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void SoundEngine::StopActorSounds(int sourcetype, const void* actor, int chanmin, int chanmax)
|
||||
{
|
||||
const bool all = (chanmin == 0 && chanmax == 0);
|
||||
if (!all && chanmax > chanmin)
|
||||
{
|
||||
const int temp = chanmax;
|
||||
chanmax = chanmin;
|
||||
chanmin = temp;
|
||||
}
|
||||
|
||||
FSoundChan* chan = Channels;
|
||||
while (chan != nullptr)
|
||||
{
|
||||
FSoundChan* next = chan->NextChan;
|
||||
if (chan->SourceType == sourcetype &&
|
||||
chan->Source == actor &&
|
||||
(all || (chan->EntChannel >= chanmin && chan->EntChannel <= chanmax)))
|
||||
{
|
||||
StopChannel(chan);
|
||||
}
|
||||
chan = next;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// S_StopAllChannels
|
||||
|
@ -1282,6 +1240,7 @@ void SoundEngine::UpdateSounds(int time)
|
|||
chan->ChanFlags &= ~CHANF_JUSTSTARTED;
|
||||
}
|
||||
|
||||
|
||||
GSnd->UpdateListener(&listener);
|
||||
GSnd->UpdateSounds();
|
||||
|
||||
|
@ -1535,7 +1494,6 @@ int SoundEngine::AddSoundLump(const char* logicalname, int lump, int CurrentPitc
|
|||
sfxinfo_t &newsfx = S_sfx.Last();
|
||||
|
||||
newsfx.data.Clear();
|
||||
newsfx.data3d.Clear();
|
||||
newsfx.name = logicalname;
|
||||
newsfx.lumpnum = lump;
|
||||
newsfx.next = 0;
|
||||
|
@ -1661,7 +1619,7 @@ unsigned int SoundEngine::GetMSLength(FSoundID sound)
|
|||
}
|
||||
}
|
||||
|
||||
sfx = LoadSound(sfx, nullptr);
|
||||
sfx = LoadSound(sfx);
|
||||
if (sfx != NULL) return GSnd->GetMSLength(sfx->data);
|
||||
else return 0;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
class AActor;
|
||||
class FScanner;
|
||||
class FSerializer;
|
||||
struct FLevelLocals;
|
||||
|
||||
#include "s_soundinternal.h"
|
||||
#include "s_doomsound.h"
|
||||
|
@ -44,8 +43,6 @@ struct FLevelLocals;
|
|||
|
||||
// Called after a level is loaded. Ensures that most sounds are loaded.
|
||||
|
||||
struct FSoundLoadBuffer;
|
||||
|
||||
// [RH] S_sfx "maintenance" routines
|
||||
void S_ClearSoundData();
|
||||
void S_ParseSndInfo (bool redefine);
|
||||
|
|
|
@ -18,9 +18,6 @@ struct sfxinfo_t
|
|||
// Next field is for use by the system sound interface.
|
||||
// A non-null data means the sound has been loaded.
|
||||
SoundHandle data;
|
||||
// Also for the sound interface. Used for 3D positional
|
||||
// sounds, may be the same as data.
|
||||
SoundHandle data3d;
|
||||
|
||||
FString name; // [RH] Sound name defined in SNDINFO
|
||||
int lumpnum; // lump number of sfx
|
||||
|
@ -59,7 +56,6 @@ struct sfxinfo_t
|
|||
void Clear()
|
||||
{
|
||||
data.Clear();
|
||||
data3d.Clear();
|
||||
lumpnum = -1; // lump number of sfx
|
||||
next = -1;
|
||||
index = 0; // [RH] For hashing
|
||||
|
@ -250,9 +246,9 @@ protected:
|
|||
TArray<uint8_t> S_SoundCurve;
|
||||
TMap<int, int> ResIdMap;
|
||||
TArray<FRandomSoundList> S_rnd;
|
||||
bool blockNewSounds = false;
|
||||
|
||||
private:
|
||||
void LoadSound3D(sfxinfo_t* sfx, FSoundLoadBuffer* pBuffer);
|
||||
void LinkChannel(FSoundChan* chan, FSoundChan** head);
|
||||
void UnlinkChannel(FSoundChan* chan);
|
||||
void ReturnChannel(FSoundChan* chan);
|
||||
|
@ -278,8 +274,13 @@ public:
|
|||
virtual ~SoundEngine() = default;
|
||||
void EvictAllChannels();
|
||||
|
||||
void BlockNewSounds(bool on)
|
||||
{
|
||||
blockNewSounds = on;
|
||||
}
|
||||
|
||||
void StopChannel(FSoundChan* chan);
|
||||
sfxinfo_t* LoadSound(sfxinfo_t* sfx, FSoundLoadBuffer* pBuffer);
|
||||
sfxinfo_t* LoadSound(sfxinfo_t* sfx);
|
||||
|
||||
// Initializes sound stuff, including volume
|
||||
// Sets channels, SFX and music volume,
|
||||
|
@ -306,12 +307,13 @@ public:
|
|||
void UpdateSounds(int time);
|
||||
|
||||
FSoundChan* StartSound(int sourcetype, const void* source,
|
||||
const FVector3* pt, int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation, FRolloffInfo* rolloff = nullptr, float spitch = 0.0f);
|
||||
const FVector3* pt, int channel, EChanFlags flags, FSoundID sound_id, float volume, float attenuation, FRolloffInfo* rolloff = nullptr, float spitch = 0.0f, float startTime = 0.0f);
|
||||
|
||||
// Stops an origin-less sound from playing from this channel.
|
||||
void StopSoundID(int sound_id);
|
||||
void StopSound(int channel, int sound_id = -1);
|
||||
void StopSound(int sourcetype, const void* actor, int channel, int sound_id = -1);
|
||||
void StopActorSounds(int sourcetype, const void* actor, int chanmin, int chanmax);
|
||||
|
||||
void RelinkSound(int sourcetype, const void* from, const void* to, const FVector3* optpos);
|
||||
void ChangeSoundVolume(int sourcetype, const void* source, int channel, double dvolume);
|
||||
|
|
|
@ -130,7 +130,7 @@ protected:
|
|||
|
||||
extern FStartupScreen *StartScreen;
|
||||
|
||||
static void DeleteStartupScreen();
|
||||
void DeleteStartupScreen();
|
||||
extern void ST_Endoom();
|
||||
|
||||
// The entire set of functions here uses native Windows types. These are recreations of those types so that the code doesn't need to be changed more than necessary
|
||||
|
|
|
@ -170,6 +170,12 @@ void SWCanvas::DrawTexture(DCanvas *canvas, FTexture *img, DrawParms &parms)
|
|||
xiscale = -xiscale;
|
||||
}
|
||||
|
||||
if (parms.flipY)
|
||||
{
|
||||
frac = (img->GetHeight() << FRACBITS) - 1;
|
||||
iyscale = -iyscale;
|
||||
}
|
||||
|
||||
if (parms.windowleft > 0 || parms.windowright < parms.texwidth)
|
||||
{
|
||||
double wi = MIN(parms.windowright, parms.texwidth);
|
||||
|
|
|
@ -94,6 +94,10 @@ public:
|
|||
TIterator operator-(difference_type offset) const { return TIterator(m_ptr - offset); }
|
||||
difference_type operator-(const TIterator &other) const { return m_ptr - other.m_ptr; }
|
||||
|
||||
// Random access operators
|
||||
T& operator[](difference_type i) { return m_ptr[i]; }
|
||||
const T& operator[](difference_type i) const { return m_ptr[i]; }
|
||||
|
||||
T &operator*() { return *m_ptr; }
|
||||
const T &operator*() const { return *m_ptr; }
|
||||
T* operator->() { return m_ptr; }
|
||||
|
|
|
@ -1056,7 +1056,7 @@ float FTexCoordInfo::TextureAdjustWidth() const
|
|||
{
|
||||
float tscale = fabs(mTempScale.X);
|
||||
if (tscale == 1.f) return (float)mRenderWidth;
|
||||
else return mWidth / fabs(tscale);
|
||||
else return mWidth / fabsf(tscale);
|
||||
}
|
||||
else return (float)mWidth;
|
||||
}
|
||||
|
|
|
@ -371,6 +371,54 @@ DEFINE_ACTION_FUNCTION(_Screen, GetViewWindow)
|
|||
return MIN(numret, 4);
|
||||
}
|
||||
|
||||
void DCanvas::CalcFullscreenScale(double srcwidth, double srcheight, int autoaspect, DoubleRect &rect) const
|
||||
{
|
||||
double aspect;
|
||||
|
||||
if (srcheight == 200) aspect = srcwidth / 240.;
|
||||
else if (srcheight == 400) aspect = srcwidth / 480;
|
||||
else aspect = srcwidth / srcheight;
|
||||
rect.left = rect.top = 0;
|
||||
auto screenratio = ActiveRatio(GetWidth(), GetHeight());
|
||||
if (autoaspect == 3)
|
||||
{
|
||||
if (screenratio >= aspect || aspect < 1.4) autoaspect = 1; // screen is wider than the image -> pillarbox it. 4:3 images must also be pillarboxed if the screen is taller than the image
|
||||
else if (screenratio > 1.32) autoaspect = 2; // on anything 4:3 and wider crop the sides of the image.
|
||||
else
|
||||
{
|
||||
// special case: Crop image to 4:3 and then letterbox this. This avoids too much cropping on narrow windows.
|
||||
double width4_3 = srcheight * (4. / 3.);
|
||||
rect.width = (double)GetWidth() * srcwidth / width4_3;
|
||||
rect.height = GetHeight() * screenratio * (3. / 4.); // use 4:3 for the image
|
||||
rect.top = (GetHeight() - rect.height) / 2;
|
||||
rect.left = -(srcwidth - width4_3) / 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((screenratio > aspect) ^ (autoaspect == 2))
|
||||
{
|
||||
// pillarboxed or vertically cropped (i.e. scale to height)
|
||||
rect.height = GetHeight();
|
||||
rect.width = GetWidth() * aspect / screenratio;
|
||||
rect.left = (GetWidth() - rect.width) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// letterboxed or horizontally cropped (i.e. scale to width)
|
||||
rect.width = GetWidth();
|
||||
rect.height = GetHeight() * screenratio / aspect;
|
||||
rect.top = (GetHeight() - rect.height) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Draw parameter parsing
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DCanvas::SetTextureParms(DrawParms *parms, FTexture *img, double xx, double yy) const
|
||||
{
|
||||
if (img != NULL)
|
||||
|
@ -418,10 +466,33 @@ bool DCanvas::SetTextureParms(DrawParms *parms, FTexture *img, double xx, double
|
|||
parms->destheight = parms->texheight * CleanYfac_1;
|
||||
break;
|
||||
|
||||
case DTA_Fullscreen:
|
||||
parms->x = parms->y = 0;
|
||||
case DTA_Base:
|
||||
if (parms->fsscalemode != -1)
|
||||
{
|
||||
// First calculate the destination rect for an image of the given size and then reposition this object in it.
|
||||
DoubleRect rect;
|
||||
CalcFullscreenScale(parms->virtWidth, parms->virtHeight, parms->fsscalemode, rect);
|
||||
parms->x = rect.left + parms->x * rect.width / parms->virtWidth;
|
||||
parms->y = rect.top + parms->y * rect.height / parms->virtHeight;
|
||||
parms->destwidth = parms->destwidth * rect.width / parms->virtWidth;
|
||||
parms->destheight = parms->destheight * rect.height / parms->virtHeight;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_Fullscreen:
|
||||
case DTA_FullscreenEx:
|
||||
{
|
||||
DoubleRect rect;
|
||||
CalcFullscreenScale(img->GetScaledWidthDouble(), img->GetScaledHeightDouble(), parms->fsscalemode, rect);
|
||||
parms->keepratio = true;
|
||||
parms->x = rect.left;
|
||||
parms->y = rect.top;
|
||||
parms->destwidth = rect.width;
|
||||
parms->destheight = rect.height;
|
||||
return false; // Do not call VirtualToRealCoords for this!
|
||||
}
|
||||
|
||||
case DTA_HUDRules:
|
||||
case DTA_HUDRulesC:
|
||||
{
|
||||
|
@ -566,6 +637,7 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t t
|
|||
parms->colorOverlay = 0;
|
||||
parms->alphaChannel = false;
|
||||
parms->flipX = false;
|
||||
parms->flipY = false;
|
||||
parms->color = 0xffffffff;
|
||||
//parms->shadowAlpha = 0;
|
||||
parms->shadowColor = 0;
|
||||
|
@ -577,13 +649,19 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t t
|
|||
parms->bilinear = false;
|
||||
parms->specialcolormap = NULL;
|
||||
parms->colormapstyle = NULL;
|
||||
parms->desaturate = 0;
|
||||
parms->cleanmode = DTA_Base;
|
||||
parms->scalex = parms->scaley = 1;
|
||||
parms->cellx = parms->celly = 0;
|
||||
parms->maxstrlen = INT_MAX;
|
||||
parms->virtBottom = false;
|
||||
parms->srcx = 0.;
|
||||
parms->srcy = 0.;
|
||||
parms->srcwidth = 1.;
|
||||
parms->srcheight = 1.;
|
||||
parms->monospace = EMonospacing::MOff;
|
||||
parms->spacing = 0;
|
||||
parms->fsscalemode = -1;
|
||||
|
||||
// Parse the tag list for attributes. (For floating point attributes,
|
||||
// consider that the C ABI dictates that all floats be promoted to
|
||||
|
@ -704,13 +782,37 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t t
|
|||
parms->virtHeight = ListGetDouble(tags);
|
||||
break;
|
||||
|
||||
case DTA_FullscreenScale:
|
||||
intval = ListGetInt(tags);
|
||||
if (intval >= 0 && intval <= 3)
|
||||
{
|
||||
parms->fsscalemode = (uint8_t)intval;
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_Fullscreen:
|
||||
|
||||
boolval = ListGetInt(tags);
|
||||
if (boolval)
|
||||
{
|
||||
assert(fortext == false);
|
||||
if (img == NULL) return false;
|
||||
parms->cleanmode = DTA_Fullscreen;
|
||||
parms->fsscalemode = (uint8_t)gameinfo.fullscreenautoaspect;
|
||||
parms->virtWidth = img->GetScaledWidthDouble();
|
||||
parms->virtHeight = img->GetScaledHeightDouble();
|
||||
}
|
||||
break;
|
||||
|
||||
case DTA_FullscreenEx:
|
||||
|
||||
intval = ListGetInt(tags);
|
||||
if (intval >= 0 && intval <= 3)
|
||||
{
|
||||
assert(fortext == false);
|
||||
if (img == NULL) return false;
|
||||
parms->cleanmode = DTA_Fullscreen;
|
||||
parms->fsscalemode = (uint8_t)intval;
|
||||
parms->virtWidth = img->GetScaledWidthDouble();
|
||||
parms->virtHeight = img->GetScaledHeightDouble();
|
||||
}
|
||||
|
@ -753,6 +855,26 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t t
|
|||
parms->flipX = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_FlipY:
|
||||
parms->flipY = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_SrcX:
|
||||
parms->srcx = ListGetDouble(tags) / img->GetScaledWidthDouble();
|
||||
break;
|
||||
|
||||
case DTA_SrcY:
|
||||
parms->srcy = ListGetDouble(tags) / img->GetScaledHeightDouble();
|
||||
break;
|
||||
|
||||
case DTA_SrcWidth:
|
||||
parms->srcwidth = ListGetDouble(tags) / img->GetScaledWidthDouble();
|
||||
break;
|
||||
|
||||
case DTA_SrcHeight:
|
||||
parms->srcheight = ListGetDouble(tags) / img->GetScaledHeightDouble();
|
||||
break;
|
||||
|
||||
case DTA_TopOffset:
|
||||
assert(fortext == false);
|
||||
if (fortext) return false;
|
||||
|
@ -904,6 +1026,10 @@ bool DCanvas::ParseDrawTextureTags(FTexture *img, double x, double y, uint32_t t
|
|||
parms->colormapstyle = ListGetColormapStyle(tags);
|
||||
break;
|
||||
|
||||
case DTA_Desaturate:
|
||||
parms->desaturate = ListGetInt(tags);
|
||||
break;
|
||||
|
||||
case DTA_TextLen:
|
||||
parms->maxstrlen = ListGetInt(tags);
|
||||
break;
|
||||
|
@ -1071,12 +1197,6 @@ void DCanvas::FillBorder (FTexture *img)
|
|||
{
|
||||
float myratio = ActiveRatio (Width, Height);
|
||||
|
||||
// if 21:9 AR, fill borders akin to 16:9, since all fullscreen
|
||||
// images are being drawn to that scale.
|
||||
if (myratio > 1.7f) {
|
||||
myratio = 16 / 9.0f;
|
||||
}
|
||||
|
||||
if (myratio >= 1.3f && myratio <= 1.4f)
|
||||
{ // This is a 4:3 display, so no border to show
|
||||
return;
|
||||
|
|
|
@ -1139,6 +1139,7 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
|
|||
ActiveColors = 0;
|
||||
SpaceWidth = 0;
|
||||
FontHeight = 0;
|
||||
int FixedWidth = 0; // hack
|
||||
|
||||
maxyoffs = 0;
|
||||
|
||||
|
@ -1199,6 +1200,14 @@ FFont::FFont (const char *name, const char *nametemplate, const char *filetempla
|
|||
sc.MustGetValue(false);
|
||||
FontHeight = sc.Number;
|
||||
}
|
||||
else if (sc.Compare("CellSize")) // hack
|
||||
{
|
||||
sc.MustGetValue(false);
|
||||
FixedWidth = sc.Number;
|
||||
sc.MustGetToken(',');
|
||||
sc.MustGetValue(false);
|
||||
FontHeight = sc.Number;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1768,7 +1777,7 @@ double GetBottomAlignOffset(FFont *font, int c)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int FFont::StringWidth(const uint8_t *string) const
|
||||
int FFont::StringWidth(const uint8_t *string, int spacing) const
|
||||
{
|
||||
int w = 0;
|
||||
int maxw = 0;
|
||||
|
@ -1798,13 +1807,17 @@ int FFont::StringWidth(const uint8_t *string) const
|
|||
maxw = w;
|
||||
w = 0;
|
||||
}
|
||||
else if (spacing >= 0)
|
||||
{
|
||||
w += GetCharWidth(chr) + GlobalKerning + spacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
w += GetCharWidth(chr) + GlobalKerning;
|
||||
w -= spacing;
|
||||
}
|
||||
}
|
||||
|
||||
return MAX(maxw, w);
|
||||
return std::max(maxw, w);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3714,10 +3727,33 @@ void V_InitFonts()
|
|||
{
|
||||
BigFont = SmallFont;
|
||||
}
|
||||
|
||||
// ugly hack for fake fonts
|
||||
if (!(NewSmallFont = V_GetFont("NewSmallFont", "SMALLFNT")))
|
||||
{
|
||||
if (Wads.CheckNumForName ("FONTA_S") >= 0)
|
||||
{
|
||||
NewSmallFont = new FFont("NewSmallFont", "FONTA%02u", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, 1, -1);
|
||||
SmallFont->SetCursor('[');
|
||||
}
|
||||
else if (Wads.CheckNumForName ("STCFN033", ns_graphics) >= 0)
|
||||
{
|
||||
NewSmallFont = new FFont("NewSmallFont", "STCFN%.3d", "defsmallfont", HU_FONTSTART, HU_FONTSIZE, HU_FONTSTART, -1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(NewConsoleFont = V_GetFont("NewConsoleFont", "CONFONT")))
|
||||
{
|
||||
NewConsoleFont = ConFont;
|
||||
}
|
||||
|
||||
if (NewSmallFont == nullptr)
|
||||
{
|
||||
NewSmallFont = SmallFont;
|
||||
}
|
||||
|
||||
// hack hack
|
||||
NewConsoleFont = ConFont;
|
||||
CurrentConsoleFont = ConFont;
|
||||
NewSmallFont = SmallFont;
|
||||
AlternativeSmallFont = SmallFont;
|
||||
OriginalSmallFont = SmallFont;
|
||||
OriginalBigFont = BigFont;
|
||||
|
|
|
@ -112,9 +112,9 @@ public:
|
|||
static void StaticPreloadFonts();
|
||||
|
||||
// Return width of string in pixels (unscaled)
|
||||
int StringWidth (const uint8_t *str) const;
|
||||
inline int StringWidth (const char *str) const { return StringWidth ((const uint8_t *)str); }
|
||||
inline int StringWidth (const FString &str) const { return StringWidth ((const uint8_t *)str.GetChars()); }
|
||||
int StringWidth (const uint8_t *str, int spacing = 0) const;
|
||||
inline int StringWidth (const char *str, int spacing = 0) const { return StringWidth ((const uint8_t *)str, spacing); }
|
||||
inline int StringWidth (const FString &str, int spacing = 0) const { return StringWidth ((const uint8_t *)str.GetChars(), spacing); }
|
||||
|
||||
inline bool CanPrint(const uint8_t *str) const { return true; } // hack hack
|
||||
|
||||
|
|
|
@ -42,6 +42,26 @@
|
|||
#include "r_data/renderstyle.h"
|
||||
#include "c_cvars.h"
|
||||
|
||||
struct DoubleRect
|
||||
{
|
||||
double left, top;
|
||||
double width, height;
|
||||
|
||||
|
||||
void Offset(double xofs, double yofs)
|
||||
{
|
||||
left += xofs;
|
||||
top += yofs;
|
||||
}
|
||||
void Scale(double xfac, double yfac)
|
||||
{
|
||||
left *= xfac;
|
||||
width *= xfac;
|
||||
top *= yfac;
|
||||
height *= yfac;
|
||||
}
|
||||
};
|
||||
|
||||
extern int CleanWidth, CleanHeight, CleanXfac, CleanYfac;
|
||||
extern int CleanWidth_1, CleanHeight_1, CleanXfac_1, CleanYfac_1;
|
||||
extern int DisplayWidth, DisplayHeight, DisplayBits;
|
||||
|
@ -110,6 +130,7 @@ enum
|
|||
DTA_BilinearFilter, // bool: apply bilinear filtering to the image
|
||||
DTA_SpecialColormap,// pointer to FSpecialColormapParameters (likely to be forever hardware-only)
|
||||
DTA_ColormapStyle, // pointer to FColormapStyle (hardware-only)
|
||||
DTA_Desaturate, // explicit desaturation factor (hack, does not do anything)
|
||||
DTA_Fullscreen, // Draw image fullscreen (same as DTA_VirtualWidth/Height with graphics size.)
|
||||
|
||||
// floating point duplicates of some of the above:
|
||||
|
@ -129,9 +150,17 @@ enum
|
|||
|
||||
// New additions.
|
||||
DTA_Color,
|
||||
DTA_FlipY, // bool: flip image vertically
|
||||
DTA_SrcX, // specify a source rectangle (this supersedes the poorly implemented DTA_WindowLeft/Right
|
||||
DTA_SrcY,
|
||||
DTA_SrcWidth,
|
||||
DTA_SrcHeight,
|
||||
DTA_LegacyRenderStyle, // takes an old-style STYLE_* constant instead of an FRenderStyle
|
||||
DTA_Spacing, // Strings only: Additional spacing between characters
|
||||
DTA_Monospace, // Fonts only: Use a fixed distance between characters.
|
||||
|
||||
DTA_FullscreenEx,
|
||||
DTA_FullscreenScale,
|
||||
};
|
||||
|
||||
enum EMonospacing : int
|
||||
|
@ -179,6 +208,7 @@ struct DrawParms
|
|||
PalEntry color;
|
||||
INTBOOL alphaChannel;
|
||||
INTBOOL flipX;
|
||||
INTBOOL flipY;
|
||||
//float shadowAlpha;
|
||||
int shadowColor;
|
||||
INTBOOL keepratio;
|
||||
|
@ -187,6 +217,7 @@ struct DrawParms
|
|||
FRenderStyle style;
|
||||
struct FSpecialColormap *specialcolormap;
|
||||
struct FColormapStyle *colormapstyle;
|
||||
int desaturate;
|
||||
int scalex, scaley;
|
||||
int cellx, celly;
|
||||
int monospace;
|
||||
|
@ -194,6 +225,10 @@ struct DrawParms
|
|||
int maxstrlen;
|
||||
bool fortext;
|
||||
bool virtBottom;
|
||||
double srcx, srcy;
|
||||
double srcwidth, srcheight;
|
||||
bool burn;
|
||||
int8_t fsscalemode;
|
||||
};
|
||||
|
||||
struct Va_List
|
||||
|
@ -319,6 +354,7 @@ public:
|
|||
void SetClipRect(int x, int y, int w, int h);
|
||||
void GetClipRect(int *x, int *y, int *w, int *h);
|
||||
|
||||
void CalcFullscreenScale(double srcwidth, double srcheight, int autoaspect, DoubleRect &rect) const;
|
||||
bool SetTextureParms(DrawParms *parms, FTexture *img, double x, double y) const;
|
||||
void DrawTexture (FTexture *img, double x, double y, int tags, ...);
|
||||
void DrawTexture(FTexture *img, double x, double y, VMVa_List &);
|
||||
|
|
|
@ -41,16 +41,16 @@ const char *GetVersionString();
|
|||
|
||||
/** Lots of different version numbers **/
|
||||
|
||||
#define VERSIONSTR "** 1.1.6-test_build_3 **"
|
||||
#define VERSIONSTR "DrBeef's QuestZDoom-1.1.6 (LZDoom 3.86)"
|
||||
|
||||
// The version as seen in the Windows resource
|
||||
#define RC_FILEVERSION 3,85,0
|
||||
#define RC_PRODUCTVERSION 3,85,0
|
||||
#define RC_FILEVERSION 3,86,0
|
||||
#define RC_PRODUCTVERSION 3,86,0
|
||||
#define RC_PRODUCTVERSION2 VERSIONSTR
|
||||
// These are for content versioning.
|
||||
#define VER_MAJOR 4
|
||||
#define VER_MINOR 3
|
||||
#define VER_REVISION 3
|
||||
#define VER_MINOR 4
|
||||
#define VER_REVISION 2
|
||||
|
||||
// Version identifier for network games.
|
||||
// Bump it every time you do a release unless you're certain you
|
||||
|
@ -60,7 +60,7 @@ const char *GetVersionString();
|
|||
// Version stored in the ini's [LastRun] section.
|
||||
// Bump it if you made some configuration change that you want to
|
||||
// be able to migrate in FGameConfigFile::DoGlobalSetup().
|
||||
#define LASTRUNVERSION "218"
|
||||
#define LASTRUNVERSION "219"
|
||||
|
||||
// Protocol version used in demos.
|
||||
// Bump it if you change existing DEM_ commands or add new ones.
|
||||
|
@ -69,7 +69,7 @@ const char *GetVersionString();
|
|||
|
||||
// Minimum demo version we can play.
|
||||
// Bump it whenever you change or remove existing DEM_ commands.
|
||||
#define MINDEMOVERSION 0x21F
|
||||
#define MINDEMOVERSION 0x221
|
||||
|
||||
// SAVEVER is the version of the information stored in level snapshots.
|
||||
// Note that SAVEVER is not directly comparable to VERSION.
|
||||
|
@ -83,7 +83,7 @@ const char *GetVersionString();
|
|||
|
||||
// Use 4500 as the base git save version, since it's higher than the
|
||||
// SVN revision ever got.
|
||||
#define SAVEVER 4556
|
||||
#define SAVEVER 4557
|
||||
|
||||
// This is so that derivates can use the same savegame versions without worrying about engine compatibility
|
||||
#define GAMESIG "LZDOOM"
|
||||
|
@ -97,7 +97,7 @@ const char *GetVersionString();
|
|||
|
||||
|
||||
// More stuff that needs to be different for derivatives.
|
||||
#define GAMENAME "QzDoom"
|
||||
#define GAMENAME "QZDoom"
|
||||
#define GAMENAMELOWERCASE "qzdoom"
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
|
|
|
@ -605,7 +605,7 @@ void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointe
|
|||
// placing the animations precisely where they belong on the base pic
|
||||
animwidth = background->GetScaledWidthDouble();
|
||||
animheight = background->GetScaledHeightDouble();
|
||||
screen->FillBorder(NULL);
|
||||
if (gameinfo.fullscreenautoaspect > 0) animwidth = 320; // deal with widescreen replacements that keep the original coordinates.
|
||||
screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE);
|
||||
}
|
||||
else
|
||||
|
@ -662,7 +662,7 @@ void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointe
|
|||
}
|
||||
if (a->ctr >= 0)
|
||||
screen->DrawTexture(a->frames[a->ctr], a->loc.x, a->loc.y,
|
||||
DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE);
|
||||
DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, DTA_FullscreenScale, gameinfo.fullscreenautoaspect, TAG_DONE);
|
||||
}
|
||||
|
||||
if (drawsplat)
|
||||
|
@ -728,6 +728,8 @@ void WI_Drawer()
|
|||
{
|
||||
IFVIRTUALPTRNAME(WI_Screen, "StatusScreen", Drawer)
|
||||
{
|
||||
screen->FillBorder(nullptr);
|
||||
screen->ClearClipRect();
|
||||
VMValue self = WI_Screen;
|
||||
VMCall(func, &self, 1, nullptr, 0);
|
||||
screen->ClearClipRect(); // make sure the scripts don't leave a valid clipping rect behind.
|
||||
|
|
|
@ -162,11 +162,6 @@ AF40D0E49BD1B76D4B1AADD8212ADC46 // MAP01 (the wad that shall not be named =P)
|
|||
limitpain
|
||||
}
|
||||
|
||||
7C1913DEE396BA26CFF22A0E9369B7D2 // Nuke Mine, e1m2
|
||||
{
|
||||
pointonline
|
||||
}
|
||||
|
||||
920F8D876ECD96D8C2A978FF1AB2B401 // Darken2.wad map01 - Nodes go out of bounds/beyond normal sector boundaries
|
||||
CFEDB7FA89885E24856CAC9A2FB3CE58 // Darken2.wad map03 - GZDoomBuilder crashes when displaying Nodes
|
||||
8E961FA7029761D5FAB3932C40F10CD2 // Darken2.wad map04 - Nodes go out of bounds/beyond normal sector boundaries
|
||||
|
@ -198,6 +193,7 @@ EDA5CE7C462BD171BF8110AC56B67857 // pl2.wad map11
|
|||
A9A9A728E689266939C1B71655F320CA // pl2.wad map25
|
||||
62CA74092FC88C1E7FE2D0B1A8034E29 // pl2.wad map29
|
||||
19E1CFD717FC6BBA9371F0F529B4CDFF // ur_final.wad map27
|
||||
836E09559FF22A7A37C2587F7EAFF1EE // Requiem MAP29 - Incorrect sector lighting and vanishing items
|
||||
{
|
||||
rebuildnodes
|
||||
}
|
||||
|
@ -255,6 +251,7 @@ D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9
|
|||
19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update
|
||||
5BDA34DA60C0530794CC1EA2DA017976 // doom2.wad map14
|
||||
5B3F118B337BFBFB8D5C81E98AF7B71D // Ancient Aliens map23
|
||||
7C1913DEE396BA26CFF22A0E9369B7D2 // Nuke Mine, e1m2
|
||||
{
|
||||
pointonline
|
||||
}
|
||||
|
|
|
@ -1914,6 +1914,7 @@ DSPLYMNU_DIMCOLOR = "Dim color";
|
|||
DSPLYMNU_MOVEBOB = "View bob amount while moving";
|
||||
DSPLYMNU_STILLBOB = "View bob amount while not moving";
|
||||
DSPLYMNU_BOBSPEED = "Weapon bob speed";
|
||||
DSPLYMNU_BOBFIRE = "Weapon bob amount while firing";
|
||||
DSPLYMNU_GPUSWITCH = "Notebook Switchable GPU";
|
||||
DSPLYMNU_CUSTOMINVERTMAP = "Custom Inverse Map";
|
||||
DSPLYMNU_CUSTOMINVERTC1 = "Custom Inverse Color Dark";
|
||||
|
@ -2216,6 +2217,7 @@ CMPTMNU_PUSHWINDOW = "Non-blocking lines can be pushed";
|
|||
CMPTMNU_CHECKSWITCHRANGE = "Enable buggy CheckSwitchRange behavior";
|
||||
CMPTMNU_EXPLODE1 = "No vertical thrust from explosions";
|
||||
CMPTMNU_EXPLODE2 = "Use original Doom explosion behavior";
|
||||
CMPTMNU_RAILINGHACK = "Enable buggy Strife railing";
|
||||
|
||||
// Sound Options
|
||||
SNDMNU_TITLE = "SOUND OPTIONS";
|
||||
|
@ -2452,6 +2454,7 @@ OPTVAL_DOOMSTRICT = "Doom (strict)";
|
|||
OPTVAL_BOOM = "Boom";
|
||||
OPTVAL_BOOMSTRICT = "Boom (strict)";
|
||||
OPTVAL_MBF = "MBF";
|
||||
OPTVAL_MBFSTRICT = "MBF (strict)";
|
||||
OPTVAL_ZDOOM2063 = "ZDoom 2.0.63";
|
||||
OPTVAL_4000HZ = "4000 Hz";
|
||||
OPTVAL_8000HZ = "8000 Hz";
|
||||
|
@ -2767,7 +2770,6 @@ GLPREFMNU_FOGMODE = "Fog mode";
|
|||
GLPREFMNU_FOGFORCEFULLBRIGHT = "Fog forces fullbright";
|
||||
GLPREFMNU_WPNLIGHTSTR = "Weapon light strength";
|
||||
GLPREFMNU_ENVIRONMENTMAPMIRROR = "Environment map on mirrors";
|
||||
GLPREFMNU_PLANEREFLECTION = "Plane Reflections (shiny floors etc)";
|
||||
GLPREFMNU_ENV = "Enhanced night vision mode";
|
||||
GLPREFMNU_ENVSTEALTH = "ENV shows stealth monsters";
|
||||
GLPREFMNU_SPRBRIGHTFOG = "Force brightness in fog";
|
||||
|
@ -2879,7 +2881,7 @@ OPTVAL_REVERSEFIRST = "Reverse";
|
|||
OPTVAL_CLASSICZ = "Classic ZDoom";
|
||||
OPTVAL_MODERN = "Modern (WASD)";
|
||||
OPTVAL_MODERN2 = "Modern (ESDF)";
|
||||
OPTVAL_MODERN3 = "Modern (IJKL)";
|
||||
OPTVAL_MODERN3 = "Modern (OKL;)";
|
||||
|
||||
// QZDoom exclusive:
|
||||
|
||||
|
|
|
@ -2733,7 +2733,6 @@ GLPREFMNU_FOGMODE = "Mode du broullard";
|
|||
GLPREFMNU_FOGFORCEFULLBRIGHT = "Brouillard force fullbright";
|
||||
GLPREFMNU_WPNLIGHTSTR = "Intensité lumineuse des armes";
|
||||
GLPREFMNU_ENVIRONMENTMAPMIRROR = "Mappage environment sur les miroirs";
|
||||
GLPREFMNU_PLANEREFLECTION = "Plane Reflections (shiny floors etc)";
|
||||
GLPREFMNU_ENV = "Mode de vision nocture amélioré";
|
||||
GLPREFMNU_ENVSTEALTH = "VNA affiche monstres invisibles";
|
||||
GLPREFMNU_SPRBRIGHTFOG = "Forcer luminosité dans brouillard";
|
||||
|
|
|
@ -219,15 +219,3 @@ skill nightmare
|
|||
MustConfirm
|
||||
Key = "n"
|
||||
}
|
||||
|
||||
skill extreme_lzd
|
||||
{
|
||||
AmmoFactor = 0.5
|
||||
DamageFactor = 2
|
||||
DisableCheats
|
||||
SpawnFilter = Hard
|
||||
PicName = "M_EXTR"
|
||||
Name = "$SKILL_EXTREME"
|
||||
MustConfirm
|
||||
NoMenu
|
||||
}
|
||||
|
|
|
@ -310,22 +310,10 @@ skill nightmare
|
|||
DoubleAmmoFactor = 1.5
|
||||
FastMonsters
|
||||
DisableCheats
|
||||
RespawnTime = 60
|
||||
SpawnFilter = Nightmare
|
||||
Name = "$MNU_BLACKPLAGUE"
|
||||
}
|
||||
|
||||
skill extreme_lzd
|
||||
{
|
||||
AmmoFactor = 0.5
|
||||
DamageFactor = 1.5
|
||||
MonsterHealth = 0.5
|
||||
HealthFactor = 0.5
|
||||
DisableCheats
|
||||
SpawnFilter = Hard
|
||||
Name = "$MNU_EXTREME"
|
||||
}
|
||||
|
||||
clearepisodes
|
||||
episode e1m1
|
||||
{
|
||||
|
|
|
@ -46,19 +46,19 @@ struct FLineTraceData
|
|||
TRACE_HasHitSky
|
||||
};
|
||||
|
||||
Actor HitActor;
|
||||
Line HitLine;
|
||||
Sector HitSector;
|
||||
F3DFloor Hit3DFloor;
|
||||
TextureID HitTexture;
|
||||
Vector3 HitLocation;
|
||||
Vector3 HitDir;
|
||||
double Distance;
|
||||
int NumPortals;
|
||||
int LineSide;
|
||||
int LinePart;
|
||||
int SectorPlane;
|
||||
int HitType;
|
||||
native Actor HitActor;
|
||||
native Line HitLine;
|
||||
native Sector HitSector;
|
||||
native F3DFloor Hit3DFloor;
|
||||
native TextureID HitTexture;
|
||||
native Vector3 HitLocation;
|
||||
native Vector3 HitDir;
|
||||
native double Distance;
|
||||
native int NumPortals;
|
||||
native int LineSide;
|
||||
native int LinePart;
|
||||
native int SectorPlane;
|
||||
native int HitType;
|
||||
}
|
||||
|
||||
struct LinkContext
|
||||
|
@ -339,17 +339,17 @@ class Actor : Thinker native
|
|||
//int ConversationRoot; // THe root of the current dialogue
|
||||
|
||||
// deprecated things.
|
||||
native readonly deprecated("2.3") double X;
|
||||
native readonly deprecated("2.3") double Y;
|
||||
native readonly deprecated("2.3") double Z;
|
||||
native readonly deprecated("2.3") double VelX;
|
||||
native readonly deprecated("2.3") double VelY;
|
||||
native readonly deprecated("2.3") double VelZ;
|
||||
native readonly deprecated("2.3") double MomX;
|
||||
native readonly deprecated("2.3") double MomY;
|
||||
native readonly deprecated("2.3") double MomZ;
|
||||
native deprecated("2.3") double ScaleX;
|
||||
native deprecated("2.3") double ScaleY;
|
||||
native readonly deprecated("2.3", "Use Pos.X instead") double X;
|
||||
native readonly deprecated("2.3", "Use Pos.Y instead") double Y;
|
||||
native readonly deprecated("2.3", "Use Pos.Z instead") double Z;
|
||||
native readonly deprecated("2.3", "Use Vel.X instead") double VelX;
|
||||
native readonly deprecated("2.3", "Use Vel.Y instead") double VelY;
|
||||
native readonly deprecated("2.3", "Use Vel.Z instead") double VelZ;
|
||||
native readonly deprecated("2.3", "Use Vel.X instead") double MomX;
|
||||
native readonly deprecated("2.3", "Use Vel.Y instead") double MomY;
|
||||
native readonly deprecated("2.3", "Use Vel.Z instead") double MomZ;
|
||||
native deprecated("2.3", "Use Scale.X instead") double ScaleX;
|
||||
native deprecated("2.3", "Use Scale.Y instead") double ScaleY;
|
||||
|
||||
//FStrifeDialogueNode *Conversation; // [RH] The dialogue to show when this actor is used.;
|
||||
|
||||
|
@ -450,7 +450,7 @@ class Actor : Thinker native
|
|||
return sin(fb * (180./32)) * 8;
|
||||
}
|
||||
|
||||
native bool isFrozen();
|
||||
native clearscope bool isFrozen() const;
|
||||
virtual native void BeginPlay();
|
||||
virtual native void Activate(Actor activator);
|
||||
virtual native void Deactivate(Actor activator);
|
||||
|
@ -459,7 +459,7 @@ class Actor : Thinker native
|
|||
virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0, Name MeansOfDeath = 'none');
|
||||
virtual native bool Slam(Actor victim);
|
||||
virtual native void Touch(Actor toucher);
|
||||
native void Substitute(Actor replacement);
|
||||
private native void Substitute(Actor replacement);
|
||||
native ui void DisplayNameTag();
|
||||
|
||||
// Called by inventory items to see if this actor is capable of touching them.
|
||||
|
@ -602,7 +602,7 @@ class Actor : Thinker native
|
|||
|
||||
native clearscope string GetTag(string defstr = "") const;
|
||||
native void SetTag(string defstr = "");
|
||||
native double GetBobOffset(double frac = 0);
|
||||
native clearscope double GetBobOffset(double frac = 0) const;
|
||||
native void ClearCounters();
|
||||
native bool GiveBody (int num, int max=0);
|
||||
native bool HitFloor();
|
||||
|
@ -698,7 +698,7 @@ class Actor : Thinker native
|
|||
native void FindFloorCeiling(int flags = 0);
|
||||
native double, double GetFriction();
|
||||
native bool, Actor TestMobjZ(bool quick = false);
|
||||
native static bool InStateSequence(State newstate, State basestate);
|
||||
native clearscope static bool InStateSequence(State newstate, State basestate);
|
||||
|
||||
bool TryWalk ()
|
||||
{
|
||||
|
@ -746,7 +746,7 @@ class Actor : Thinker native
|
|||
native bool LookForEnemies(bool allaround, LookExParams params = null);
|
||||
native bool LookForPlayers(bool allaround, LookExParams params = null);
|
||||
native bool TeleportMove(Vector3 pos, bool telefrag, bool modifyactor = true);
|
||||
native double DistanceBySpeed(Actor other, double speed);
|
||||
native clearscope double DistanceBySpeed(Actor other, double speed) const;
|
||||
native name GetSpecies();
|
||||
native void PlayActiveSound();
|
||||
native void Howl();
|
||||
|
@ -754,6 +754,7 @@ class Actor : Thinker native
|
|||
native void GiveSecret(bool printmsg = true, bool playsound = true);
|
||||
native clearscope double GetCameraHeight() const;
|
||||
native clearscope double GetGravity() const;
|
||||
native void DoMissileDamage(Actor target);
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -781,7 +782,7 @@ class Actor : Thinker native
|
|||
return level.totaltime - SpawnTime;
|
||||
}
|
||||
|
||||
double AccuracyFactor()
|
||||
clearscope double AccuracyFactor() const
|
||||
{
|
||||
return 1. / (1 << (accuracy * 5 / 100));
|
||||
}
|
||||
|
@ -901,7 +902,7 @@ class Actor : Thinker native
|
|||
return true;
|
||||
}
|
||||
|
||||
deprecated("2.3") void A_FaceConsolePlayer(double MaxTurnAngle = 0) {}
|
||||
deprecated("2.3", "This function does nothing and is only for Zandronum compatibility") void A_FaceConsolePlayer(double MaxTurnAngle = 0) {}
|
||||
|
||||
void A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0)
|
||||
{
|
||||
|
@ -1047,16 +1048,18 @@ class Actor : Thinker native
|
|||
native void A_Wander(int flags = 0);
|
||||
native void A_Look2();
|
||||
|
||||
deprecated("2.3") native void A_BulletAttack();
|
||||
deprecated("2.3", "Use A_CustomBulletAttack() instead") native void A_BulletAttack();
|
||||
native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class<Actor> pufftype = "BulletPuff");
|
||||
deprecated("4.3") native clearscope void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false, double pitch = 0.0);
|
||||
native clearscope void A_StartSound(sound whattoplay, int slot = CHAN_BODY, int flags = 0, double volume = 1.0, double attenuation = ATTN_NORM, double pitch = 0.0);
|
||||
deprecated("4.3", "Use A_StartSound() instead") native clearscope void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false, double pitch = 0.0);
|
||||
native clearscope void A_StartSound(sound whattoplay, int slot = CHAN_BODY, int flags = 0, double volume = 1.0, double attenuation = ATTN_NORM, double pitch = 0.0, double startTime = 0.0);
|
||||
native void A_SoundVolume(int slot, double volume);
|
||||
native void A_SoundPitch(int slot, double pitch);
|
||||
deprecated("2.3") void A_PlayWeaponSound(sound whattoplay) { A_StartSound(whattoplay, CHAN_WEAPON); }
|
||||
deprecated("2.3", "Use A_StartSound(<sound>, CHAN_WEAPON) instead") void A_PlayWeaponSound(sound whattoplay) { A_StartSound(whattoplay, CHAN_WEAPON); }
|
||||
native void A_StopSound(int slot = CHAN_VOICE); // Bad default but that's what is originally was...
|
||||
deprecated("2.3") native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0);
|
||||
deprecated("2.3") native void A_StopSoundEx(name slot);
|
||||
void A_StopAllSounds() { A_StopSounds(0,0); }
|
||||
native void A_StopSounds(int chanmin, int chanmax);
|
||||
deprecated("2.3", "Use A_StartSound() instead") native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0);
|
||||
deprecated("2.3", "Use A_StopSound() instead") native void A_StopSoundEx(name slot);
|
||||
native clearscope bool IsActorPlayingSound(int channel, Sound snd = 0);
|
||||
native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10);
|
||||
native action state A_Jump(int chance, statelabel label, ...);
|
||||
|
@ -1077,7 +1080,7 @@ class Actor : Thinker native
|
|||
native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false);
|
||||
native void A_DropInventory(class<Inventory> itemtype, int amount = -1);
|
||||
native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0, double alpha2 = 0.);
|
||||
deprecated("2.3") native void A_ChangeFlag(string flagname, bool value);
|
||||
deprecated("2.3", "Use 'b<FlagName> = [true/false]' instead") native void A_ChangeFlag(string flagname, bool value);
|
||||
native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE);
|
||||
native void A_RaiseMaster(int flags = 0);
|
||||
native void A_RaiseChildren(int flags = 0);
|
||||
|
@ -1113,10 +1116,10 @@ class Actor : Thinker native
|
|||
native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
|
||||
native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT);
|
||||
native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT);
|
||||
deprecated("2.3") native void A_SetUserVar(name varname, int value);
|
||||
deprecated("2.3") native void A_SetUserArray(name varname, int index, int value);
|
||||
deprecated("2.3") native void A_SetUserVarFloat(name varname, double value);
|
||||
deprecated("2.3") native void A_SetUserArrayFloat(name varname, int index, double value);
|
||||
deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserVar(name varname, int value);
|
||||
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(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake");
|
||||
native void A_QuakeEx(int intensityX, int intensityY, int 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);
|
||||
action native void A_SetTics(int tics);
|
||||
|
@ -1149,8 +1152,9 @@ class Actor : Thinker native
|
|||
native bool A_SetVisibleRotation(double anglestart = 0, double angleend = 0, double pitchstart = 0, double pitchend = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
|
||||
native void A_SetTranslation(name transname);
|
||||
native bool A_SetSize(double newradius = -1, double newheight = -1, bool testpos = false);
|
||||
native void A_SprayDecal(String name, double dist = 172);
|
||||
native void A_SprayDecal(String name, double dist = 172, vector3 offset = (0, 0, 0), vector3 direction = (0, 0, 0) );
|
||||
native void A_SetMugshotState(String name);
|
||||
native void CopyBloodColor(Actor other);
|
||||
|
||||
native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0);
|
||||
native void A_TransferPointer(int ptr_source, int ptr_recipient, int sourcefield, int recipientfield=AAPTR_DEFAULT, int flags=0);
|
||||
|
|
|
@ -686,18 +686,18 @@ extend class Actor
|
|||
}
|
||||
}
|
||||
|
||||
deprecated("2.3") void A_MeleeAttack()
|
||||
deprecated("2.3", "Use CustomMeleeAttack() instead") void A_MeleeAttack()
|
||||
{
|
||||
DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0);
|
||||
}
|
||||
|
||||
deprecated("2.3") void A_MissileAttack()
|
||||
deprecated("2.3", "Use A_SpawnProjectile() instead") void A_MissileAttack()
|
||||
{
|
||||
Class<Actor> MissileType = MissileName;
|
||||
DoAttack(false, true, 0, 0, MissileType, MissileHeight);
|
||||
}
|
||||
|
||||
deprecated("2.3") void A_ComboAttack()
|
||||
deprecated("2.3", "Use A_BasicAttack() instead") void A_ComboAttack()
|
||||
{
|
||||
Class<Actor> MissileType = MissileName;
|
||||
DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight);
|
||||
|
|
|
@ -168,7 +168,7 @@ extend class Actor
|
|||
|
||||
private native bool CheckFlag(string flagname, int check_pointer = AAPTR_DEFAULT);
|
||||
|
||||
deprecated("2.3") action state A_CheckFlag(string flagname, statelabel label, int check_pointer = AAPTR_DEFAULT)
|
||||
deprecated("2.3", "Use a combination of direct flag access and SetStateLabel()") action state A_CheckFlag(string flagname, statelabel label, int check_pointer = AAPTR_DEFAULT)
|
||||
{
|
||||
return CheckFlag(flagname, check_pointer)? ResolveState(label) : null;
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ extend class Actor
|
|||
aimtarget.Height = Height;
|
||||
|
||||
bool shootmode = ((flags & MSF_Classic) || // Flag explicitly set, or no flags and compat options
|
||||
(flags == 0 && CurState.bDehacked && (Level.compatflags & COMPATF_MUSHROOM)));
|
||||
(flags == 0 && CurState.bDehacked && (compatflags & COMPATF_MUSHROOM)));
|
||||
|
||||
for (i = -numspawns; i <= numspawns; i += 8)
|
||||
{
|
||||
|
|
|
@ -86,7 +86,7 @@ extend class Actor
|
|||
}
|
||||
|
||||
// [RH] make this optional
|
||||
if (limit < 0 && (Level.compatflags & COMPATF_LIMITPAIN))
|
||||
if (limit < 0 && (compatflags & COMPATF_LIMITPAIN))
|
||||
limit = 21;
|
||||
|
||||
if (limit > 0)
|
||||
|
|
|
@ -70,9 +70,13 @@ extend class StateProvider
|
|||
{
|
||||
// Removed most of the mess that was here in the C++ code because SetSafeFlash already does some thorough validation.
|
||||
State atk = weap.FindState('Fire');
|
||||
State cur = player.GetPSprite(PSP_WEAPON).CurState;
|
||||
let psp = player.GetPSprite(PSP_WEAPON);
|
||||
if (psp)
|
||||
{
|
||||
State cur = psp.CurState;
|
||||
int theflash = atk == cur? 0:1;
|
||||
player.SetSafeFlash(weap, flash, theflash);
|
||||
}
|
||||
}
|
||||
}
|
||||
player.mo.PlayAttacking2 ();
|
||||
|
|
|
@ -56,7 +56,11 @@ class Beak : Weapon
|
|||
{
|
||||
return;
|
||||
}
|
||||
player.GetPSprite(PSP_WEAPON).y = WEAPONTOP;
|
||||
let psp = player.GetPSprite(PSP_WEAPON);
|
||||
if (psp)
|
||||
{
|
||||
psp.y = WEAPONTOP;
|
||||
}
|
||||
player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState());
|
||||
}
|
||||
|
||||
|
@ -85,7 +89,11 @@ class Beak : Weapon
|
|||
}
|
||||
A_StartSound ("chicken/peck", CHAN_VOICE);
|
||||
player.chickenPeck = 12;
|
||||
player.GetPSprite(PSP_WEAPON).Tics -= random[BeakAtk](0,7);
|
||||
let psp = player.GetPSprite(PSP_WEAPON);
|
||||
if (psp)
|
||||
{
|
||||
psp.Tics -= random[BeakAtk](0,7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +141,11 @@ class BeakPowered : Beak
|
|||
}
|
||||
A_StartSound ("chicken/peck", CHAN_VOICE);
|
||||
player.chickenPeck = 12;
|
||||
player.GetPSprite(PSP_WEAPON).Tics -= random[BeakAtk](0,3);
|
||||
let psp = player.GetPSprite(PSP_WEAPON);
|
||||
if (psp)
|
||||
{
|
||||
psp.Tics -= random[BeakAtk](0,3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue