Update to LZDoom 3.86

This commit is contained in:
Simon 2020-11-02 21:16:25 +00:00
parent 9d6e140f7c
commit fede580be9
133 changed files with 2364 additions and 1364 deletions

View file

@ -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. -->

View file

@ -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;

View file

@ -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;

View file

@ -95,7 +95,7 @@ inline double AActor::AttackOffset(double offset)
}
inline bool AActor::isFrozen()
inline bool AActor::isFrozen() const
{
if (!(flags5 & MF5_NOTIMEFREEZE))
{

View file

@ -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;

View file

@ -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)
{

View file

@ -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) {}

View file

@ -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,

View file

@ -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));

View file

@ -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;
}
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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;
};

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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.

View file

@ -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)
{

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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
{

View file

@ -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;
};

View file

@ -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;

View file

@ -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)
{

View file

@ -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)
{

View file

@ -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;

View file

@ -946,6 +946,7 @@ void FGLRenderer::RenderView (player_t* player)
{
GLRenderer->NextVtxBuffer();
GLRenderer->NextSkyBuffer();
GLRenderer->NextLightBuffer();
if (gl_sync) {
GLRenderer->GPUWaitSync();

View file

@ -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))
{

View file

@ -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];

View file

@ -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;
}

View file

@ -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);

View file

@ -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"
//==========================================================================
//

View file

@ -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);
}

View file

@ -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)

View file

@ -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)
{

View file

@ -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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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))
{

View file

@ -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;
}

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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
{

View file

@ -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;

View file

@ -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
{

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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)
{

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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++;

View file

@ -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);

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -28,6 +28,8 @@
* unsigned int and 64-bit unsigned int in hexadecimal format.
*/
#include <inttypes.h>
#ifndef SFMT_H
#define SFMT_H

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}
//==========================================================================
//

View file

@ -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);

View file

@ -55,6 +55,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdexcept>
#ifdef _WIN32
#include <io.h>
#include "musicformats/win32/i_cd.h"

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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; }

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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 &);

View file

@ -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)

View file

@ -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.

View file

@ -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
}

View file

@ -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:

View file

@ -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";

View file

@ -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
}

View file

@ -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
{

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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)
{

View file

@ -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)

View file

@ -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 ();

View file

@ -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