qzdoom/src/gamedata/info.h

450 lines
10 KiB
C
Raw Normal View History

2016-03-01 15:47:10 +00:00
/*
** info.h
**
**---------------------------------------------------------------------------
** Copyright 1998-2007 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifndef __INFO_H__
#define __INFO_H__
#include <stddef.h>
#include <stdint.h>
2016-03-01 15:47:10 +00:00
#include "dobject.h"
#include "doomdef.h"
#include "s_sound.h"
#include "m_fixed.h"
#include "m_random.h"
struct Baggage;
class FScanner;
struct FActorInfo;
class FIntCVar;
class FStateDefinitions;
class FInternalLightAssociation;
2016-03-01 15:47:10 +00:00
enum EStateDefineFlags
{
SDF_NEXT = 0,
SDF_STATE = 1,
SDF_STOP = 2,
SDF_WAIT = 3,
SDF_LABEL = 4,
SDF_INDEX = 5,
SDF_MASK = 7,
};
enum EStateFlags
{
STF_SLOW = 1, // State duration is extended when slow monsters is on.
STF_FAST = 2, // State duration is shortened when fast monsters is on.
STF_FULLBRIGHT = 4, // State is fullbright
STF_NODELAY = 8, // Spawn states executes its action normally
STF_SAMEFRAME = 16, // Ignore Frame (except when spawning actor)
STF_CANRAISE = 32, // Allows a monster to be resurrected without waiting for an infinate frame
STF_DEHACKED = 64, // Modified by Dehacked
};
enum EStateUseFlags
{
SUF_ACTOR = 1,
SUF_OVERLAY = 2,
SUF_WEAPON = 4,
SUF_ITEM = 8,
};
enum EStateType : int // this must ensure proper alignment.
{
STATE_Actor,
STATE_Psprite,
STATE_StateChain,
};
struct FStateParamInfo
{
FState *mCallingState;
EStateType mStateType;
int mPSPIndex;
};
2016-03-01 15:47:10 +00:00
// Sprites that are fixed in position because they can have special meanings.
enum
{
SPR_TNT1, // The empty sprite
SPR_FIXED, // Do not change sprite or frame
SPR_NOCHANGE, // Do not change sprite (frame change is okay)
};
struct FState
{
FState *NextState;
VMFunction *ActionFunc;
int32_t sprite;
int16_t Tics;
uint16_t TicRange;
int16_t Light;
uint16_t StateFlags;
uint8_t Frame;
uint8_t UseFlags;
uint8_t DefineFlags;
2017-03-08 17:47:52 +00:00
int32_t Misc1; // Was changed to int8_t, reverted to long for MBF compat
int32_t Misc2; // Was changed to uint8_t, reverted to long for MBF compat
public:
2016-03-01 15:47:10 +00:00
inline int GetFrame() const
{
return Frame;
}
inline bool GetSameFrame() const
{
return !!(StateFlags & STF_SAMEFRAME);
2016-03-01 15:47:10 +00:00
}
inline int GetFullbright() const
{
return (StateFlags & STF_FULLBRIGHT)? 0x10 /*RF_FULLBRIGHT*/ : 0;
}
inline bool GetFast() const
{
return !!(StateFlags & STF_FAST);
}
inline bool GetSlow() const
{
return !!(StateFlags & STF_SLOW);
}
inline bool GetNoDelay() const
{
return !!(StateFlags & STF_NODELAY);
}
inline bool GetCanRaise() const
{
return !!(StateFlags & STF_CANRAISE);
2016-03-01 15:47:10 +00:00
}
inline int GetTics() const
{
if (TicRange == 0)
{
return Tics;
}
return Tics + pr_statetics.GenRand32() % (TicRange + 1);
}
inline int GetMisc1() const
{
return Misc1;
}
inline int GetMisc2() const
{
return Misc2;
}
inline FState *GetNextState() const
{
return NextState;
}
2017-03-08 17:47:52 +00:00
inline void SetFrame(uint8_t frame)
2016-03-01 15:47:10 +00:00
{
Frame = frame - 'A';
}
void SetAction(VMFunction *func) { ActionFunc = func; }
void ClearAction() { ActionFunc = NULL; }
void SetAction(const char *name);
bool CallAction(AActor *self, AActor *stateowner, FStateParamInfo *stateinfo, FState **stateret);
void CheckCallerType(AActor *self, AActor *stateowner);
2016-03-01 15:47:10 +00:00
static PClassActor *StaticFindStateOwner (const FState *state);
static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info);
static FString StaticGetStateName(const FState *state);
2016-03-01 15:47:10 +00:00
static FRandom pr_statetics;
2016-03-01 15:47:10 +00:00
};
struct FStateLabels;
struct FStateLabel
{
FName Label;
FState *State;
FStateLabels *Children;
};
struct FStateLabels
{
int NumLabels;
FStateLabel Labels[1];
FStateLabel *FindLabel (FName label);
void Destroy(); // intentionally not a destructor!
};
#include "gametype.h"
struct DmgFactors : public TArray<std::pair<FName, double>>
2016-03-01 15:47:10 +00:00
{
int Apply(FName type, int damage);
2016-03-01 15:47:10 +00:00
};
typedef TArray<std::pair<FName, int>> PainChanceList;
2016-03-01 15:47:10 +00:00
struct DamageTypeDefinition
{
public:
DamageTypeDefinition() { Clear(); }
FString Obituary;
double DefaultFactor;
2016-03-01 15:47:10 +00:00
bool ReplaceFactor;
bool NoArmor;
void Apply(FName type);
void Clear()
{
Obituary = "";
DefaultFactor = 1.;
2016-03-01 15:47:10 +00:00
ReplaceFactor = false;
NoArmor = false;
}
static bool IgnoreArmor(FName type);
static int ApplyMobjDamageFactor(int damage, FName type, DmgFactors const * const factors);
static FString GetObituary(FName type);
private:
static double GetMobjDamageFactor(FName type, DmgFactors const * const factors);
static DamageTypeDefinition *Get(FName type);
2016-03-01 15:47:10 +00:00
};
struct FDropItem;
2016-03-01 15:47:10 +00:00
struct FActorInfo
{
TArray<FInternalLightAssociation *> LightAssociations;
PClassActor *Replacement = nullptr;
PClassActor *Replacee = nullptr;
FState *OwnedStates = nullptr;
int NumOwnedStates = 0;
bool SkipSuperSet = false;
uint8_t GameFilter = GAME_Any;
uint16_t SpawnID = 0;
uint16_t ConversationID = 0;
int16_t DoomEdNum = -1;
FStateLabels *StateList = nullptr;
DmgFactors DamageFactors;
PainChanceList PainChances;
TArray<PClassActor *> VisibleToPlayerClass;
FDropItem *DropItems;
FIntCVar *distancecheck;
// This is from PClassPlayerPawn
FString DisplayName;
uint8_t DefaultStateUsage = 0; // state flag defaults for blocks without a qualifier.
FActorInfo() {}
FActorInfo(const FActorInfo & other)
{
// only copy the fields that get inherited
DefaultStateUsage = other.DefaultStateUsage;
DamageFactors = other.DamageFactors;
PainChances = other.PainChances;
VisibleToPlayerClass = other.VisibleToPlayerClass;
DropItems = other.DropItems;
distancecheck = other.distancecheck;
DisplayName = other.DisplayName;
}
~FActorInfo()
{
if (StateList != NULL)
{
StateList->Destroy();
M_Free(StateList);
}
}
};
// This is now merely a wrapper that adds actor-specific functionality to PClass.
// No objects of this type will be created ever - its only use is to static_cast
// PClass to it.
2016-03-01 15:47:10 +00:00
class PClassActor : public PClass
{
protected:
public:
static void StaticInit ();
static void StaticSetActorNums ();
void BuildDefaults();
2017-03-08 17:47:52 +00:00
void ApplyDefaults(uint8_t *defaults);
2016-03-01 15:47:10 +00:00
void RegisterIDs();
void SetDamageFactor(FName type, double factor);
2016-03-01 15:47:10 +00:00
void SetPainChance(FName type, int chance);
bool SetReplacement(FName replaceName);
2016-03-01 15:47:10 +00:00
FActorInfo *ActorInfo() const
{
return (FActorInfo*)Meta;
}
void SetDropItems(FDropItem *drops)
{
ActorInfo()->DropItems = drops;
}
const FString &GetDisplayName() const
{
return ActorInfo()->DisplayName;
}
FState *GetStates() const
{
return ActorInfo()->OwnedStates;
}
unsigned GetStateCount() const
{
return ActorInfo()->NumOwnedStates;
}
FStateLabels *GetStateLabels() const
{
return ActorInfo()->StateList;
}
2016-03-01 15:47:10 +00:00
FState *FindState(int numnames, FName *names, bool exact=false) const;
FState *FindStateByString(const char *name, bool exact=false);
FState *FindState(FName name) const
{
return FindState(1, &name);
}
bool OwnsState(const FState *state)
{
auto i = ActorInfo();
return i != nullptr && state >= i->OwnedStates && state < i->OwnedStates + i->NumOwnedStates;
2016-03-01 15:47:10 +00:00
}
PClassActor *GetReplacement(FLevelLocals *Level, bool lookskill=true);
PClassActor *GetReplacee(FLevelLocals *Level, bool lookskill=true);
2016-03-01 15:47:10 +00:00
// For those times when being able to scan every kind of actor is convenient
static TArray<PClassActor *> AllActorClasses;
};
struct FDoomEdEntry
{
PClassActor *Type;
short Special;
signed char ArgsDefined;
bool NoSkillFlags;
2016-03-01 15:47:10 +00:00
int Args[5];
};
- fixed: State labels were resolved in the calling function's context instead of the called function one's. This could cause problems with functions that take states as parameters but use them to set them internally instead of passing them through the A_Jump interface back to the caller, like A_Chase or A_LookEx. This required some quite significant refactoring because the entire state resolution logic had been baked into the compiler which turned out to be a major maintenance problem. Fixed this by adding a new builtin type 'statelabel'. This is an opaque identifier representing a state, with the actual data either directly encoded into the number for single label state or an index into a state information table. The state resolution is now the task of the called function as it should always have remained. Note, that this required giving back the 'action' qualifier to most state jumping functions. - refactored most A_Jump checkers to a two stage setup with a pure checker that returns a boolean and a scripted A_Jump wrapper, for some simpler checks the checker function was entirely omitted and calculated inline in the A_Jump function. It is strongly recommended to use the boolean checkers unless using an inline function invocation in a state as they lead to vastly clearer code and offer more flexibility. - let Min() and Max() use the OP_MIN and OP_MAX opcodes. Although these were present, these function were implemented using some grossly inefficient branching tests. - the DECORATE 'state' cast kludge will now actually call ResolveState because a state label is not a state and needs conversion.
2016-11-14 13:12:27 +00:00
struct FStateLabelStorage
{
TArray<uint8_t> Storage;
int AddPointer(FState *ptr)
{
if (ptr != nullptr)
{
int pos = Storage.Reserve(sizeof(ptr) + sizeof(int));
memset(&Storage[pos], 0, sizeof(int));
memcpy(&Storage[pos + sizeof(int)], &ptr, sizeof(ptr));
return pos / 4 + 1;
}
else return 0;
}
int AddNames(TArray<FName> &names)
{
int siz = names.Size();
if (siz > 1)
{
int pos = Storage.Reserve(sizeof(int) + sizeof(FName) * names.Size());
memcpy(&Storage[pos], &siz, sizeof(int));
memcpy(&Storage[pos + sizeof(int)], &names[0], sizeof(FName) * names.Size());
return pos / 4 + 1;
}
else
{
// don't store single name states in the array.
return names[0].GetIndex() + 0x10000000;
}
}
FState *GetState(int pos, PClassActor *cls, bool exact = false);
- fixed: State labels were resolved in the calling function's context instead of the called function one's. This could cause problems with functions that take states as parameters but use them to set them internally instead of passing them through the A_Jump interface back to the caller, like A_Chase or A_LookEx. This required some quite significant refactoring because the entire state resolution logic had been baked into the compiler which turned out to be a major maintenance problem. Fixed this by adding a new builtin type 'statelabel'. This is an opaque identifier representing a state, with the actual data either directly encoded into the number for single label state or an index into a state information table. The state resolution is now the task of the called function as it should always have remained. Note, that this required giving back the 'action' qualifier to most state jumping functions. - refactored most A_Jump checkers to a two stage setup with a pure checker that returns a boolean and a scripted A_Jump wrapper, for some simpler checks the checker function was entirely omitted and calculated inline in the A_Jump function. It is strongly recommended to use the boolean checkers unless using an inline function invocation in a state as they lead to vastly clearer code and offer more flexibility. - let Min() and Max() use the OP_MIN and OP_MAX opcodes. Although these were present, these function were implemented using some grossly inefficient branching tests. - the DECORATE 'state' cast kludge will now actually call ResolveState because a state label is not a state and needs conversion.
2016-11-14 13:12:27 +00:00
};
extern FStateLabelStorage StateLabels;
2016-03-01 15:47:10 +00:00
enum ESpecialMapthings
{
SMT_Player1Start = 1,
SMT_Player2Start,
SMT_Player3Start,
SMT_Player4Start,
SMT_Player5Start,
SMT_Player6Start,
SMT_Player7Start,
SMT_Player8Start,
SMT_DeathmatchStart,
SMT_SSeqOverride,
SMT_PolyAnchor,
SMT_PolySpawn,
SMT_PolySpawnCrush,
SMT_PolySpawnHurt,
SMT_SlopeFloorPointLine,
SMT_SlopeCeilingPointLine,
SMT_SetFloorSlope,
SMT_SetCeilingSlope,
SMT_VavoomFloor,
SMT_VavoomCeiling,
SMT_CopyFloorPlane,
SMT_CopyCeilingPlane,
SMT_VertexFloorZ,
SMT_VertexCeilingZ,
SMT_EDThing,
};
typedef TMap<int, FDoomEdEntry> FDoomEdMap;
extern FDoomEdMap DoomEdMap;
void InitActorNumsFromMapinfo();
int GetSpriteIndex(const char * spritename, bool add = true);
TArray<FName> &MakeStateNameList(const char * fname);
void AddStateLight(FState *state, const char *lname);
#endif // __INFO_H__