mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-25 05:11:04 +00:00
Merge branch 'master' of https://github.com/coelckers/gzdoom
This commit is contained in:
commit
d298cc7414
80 changed files with 1264 additions and 873 deletions
|
@ -263,8 +263,8 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
gravity = <float>; // Set per-actor gravity. Positive values are multiplied with the class's property,
|
||||
// negative values are used as their absolute. Default = 1.0.
|
||||
|
||||
health = <int>; // Set per-actor health as an absolute value. Default = actor default.
|
||||
healthfactor = <float>; // Set per-actor health as a factor to the original. Default = 1.
|
||||
health = <float>; // Set per-actor health. Positive values are multiplied with the class's property,
|
||||
// negative values are used as their absolute. Default = 1.
|
||||
|
||||
renderstyle = <string>; // Set per-actor render style, overriding the class default. Possible values can be "normal",
|
||||
// "none", "add" or "additive", "subtract" or "subtractive", "stencil", "translucentstencil",
|
||||
|
|
|
@ -260,5 +260,7 @@ DEFINE_SPECIAL(Stairs_BuildUpDoomSync, 271, 4, 4, 4)
|
|||
DEFINE_SPECIAL(Stairs_BuildDownDoomSync, 272, 4, 4, 4)
|
||||
DEFINE_SPECIAL(Stairs_BuildUpDoomCrush, 273, 5, 5, 5)
|
||||
DEFINE_SPECIAL(Door_AnimatedClose, 274, 4, 4, 4)
|
||||
DEFINE_SPECIAL(Floor_Stop, 275, 1, 1, 1)
|
||||
DEFINE_SPECIAL(Ceiling_Stop, 276, 1, 1, 1)
|
||||
|
||||
#undef DEFINE_SPECIAL
|
||||
|
|
85
src/actor.h
85
src/actor.h
|
@ -808,42 +808,12 @@ public:
|
|||
return (flags & MF_COUNTKILL) && !(flags & MF_FRIENDLY);
|
||||
}
|
||||
|
||||
PalEntry GetBloodColor() const
|
||||
{
|
||||
return GetClass()->BloodColor;
|
||||
}
|
||||
|
||||
// These also set CF_INTERPVIEW for players.
|
||||
void SetPitch(DAngle p, bool interpolate, bool forceclamp = false);
|
||||
void SetAngle(DAngle ang, bool interpolate);
|
||||
void SetRoll(DAngle roll, bool interpolate);
|
||||
|
||||
PClassActor *GetBloodType(int type = 0) const
|
||||
{
|
||||
PClassActor *bloodcls;
|
||||
if (type == 0)
|
||||
{
|
||||
bloodcls = PClass::FindActor(GetClass()->BloodType);
|
||||
}
|
||||
else if (type == 1)
|
||||
{
|
||||
bloodcls = PClass::FindActor(GetClass()->BloodType2);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
bloodcls = PClass::FindActor(GetClass()->BloodType3);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bloodcls != NULL)
|
||||
{
|
||||
bloodcls = bloodcls->GetReplacement();
|
||||
}
|
||||
return bloodcls;
|
||||
}
|
||||
PClassActor *GetBloodType(int type = 0) const;
|
||||
|
||||
double Distance2DSquared(AActor *other, bool absolute = false)
|
||||
{
|
||||
|
@ -1009,29 +979,42 @@ public:
|
|||
// NOTE: The first member variable *must* be snext.
|
||||
AActor *snext, **sprev; // links in sector (if needed)
|
||||
DVector3 __Pos; // double underscores so that it won't get used by accident. Access to this should be exclusively through the designated access functions.
|
||||
DVector3 OldRenderPos;
|
||||
|
||||
DAngle SpriteAngle;
|
||||
DAngle SpriteRotation;
|
||||
DAngle VisibleStartAngle;
|
||||
DAngle VisibleStartPitch;
|
||||
DAngle VisibleEndAngle;
|
||||
DAngle VisibleEndPitch;
|
||||
DRotator Angles;
|
||||
DVector3 Vel;
|
||||
double Speed;
|
||||
double FloatSpeed;
|
||||
DVector2 Scale; // Scaling values; 1 is normal size
|
||||
double Alpha; // Since P_CheckSight makes an alpha check this can't be a float. It has to be a double.
|
||||
|
||||
int sprite; // used to find patch_t and flip value
|
||||
uint8_t frame; // sprite frame to draw
|
||||
uint8_t effects; // [RH] see p_effect.h
|
||||
uint8_t fountaincolor; // Split out of 'effect' to have easier access.
|
||||
DVector2 Scale; // Scaling values; 1 is normal size
|
||||
FRenderStyle RenderStyle; // Style to draw this actor with
|
||||
ActorRenderFlags renderflags; // Different rendering flags
|
||||
FTextureID picnum; // Draw this instead of sprite if valid
|
||||
double Alpha; // Since P_CheckSight makes an alpha check this can't be a float. It has to be a double.
|
||||
DWORD fillcolor; // Color to draw when STYLE_Shaded
|
||||
DWORD Translation;
|
||||
|
||||
ActorRenderFlags renderflags; // Different rendering flags
|
||||
ActorFlags flags;
|
||||
ActorFlags2 flags2; // Heretic flags
|
||||
ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable
|
||||
ActorFlags4 flags4; // [RH] Even more flags!
|
||||
ActorFlags5 flags5; // OMG! We need another one.
|
||||
ActorFlags6 flags6; // Shit! Where did all the flags go?
|
||||
ActorFlags7 flags7; // WHO WANTS TO BET ON 8!?
|
||||
double Floorclip; // value to use for floor clipping
|
||||
double radius, Height; // for movement checking
|
||||
|
||||
DAngle VisibleStartAngle;
|
||||
DAngle VisibleStartPitch;
|
||||
DAngle VisibleEndAngle;
|
||||
DAngle VisibleEndPitch;
|
||||
|
||||
DVector3 OldRenderPos;
|
||||
DVector3 Vel;
|
||||
double Speed;
|
||||
double FloatSpeed;
|
||||
|
||||
// interaction info
|
||||
FBlockNode *BlockNode; // links in blocks (if needed)
|
||||
|
@ -1045,10 +1028,15 @@ public:
|
|||
int floorterrain;
|
||||
struct sector_t *ceilingsector;
|
||||
FTextureID ceilingpic; // contacted sec ceilingpic
|
||||
double radius, Height; // for movement checking
|
||||
double renderradius;
|
||||
|
||||
double projectilepassheight; // height for clipping projectile movement against this actor
|
||||
double CameraHeight; // Height of camera when used as such
|
||||
|
||||
double RadiusDamageFactor; // Radius damage factor
|
||||
double SelfDamageFactor;
|
||||
double StealthAlpha; // Minmum alpha for MF_STEALTH.
|
||||
int WoundHealth; // Health needed to enter wound state
|
||||
|
||||
SDWORD tics; // state tic counter
|
||||
FState *state;
|
||||
|
@ -1056,13 +1044,6 @@ public:
|
|||
int DamageVal;
|
||||
VMFunction *DamageFunc;
|
||||
int projectileKickback;
|
||||
ActorFlags flags;
|
||||
ActorFlags2 flags2; // Heretic flags
|
||||
ActorFlags3 flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable
|
||||
ActorFlags4 flags4; // [RH] Even more flags!
|
||||
ActorFlags5 flags5; // OMG! We need another one.
|
||||
ActorFlags6 flags6; // Shit! Where did all the flags go?
|
||||
ActorFlags7 flags7; // WHO WANTS TO BET ON 8!?
|
||||
|
||||
// [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it.
|
||||
DWORD VisibleToTeam;
|
||||
|
@ -1100,7 +1081,6 @@ public:
|
|||
TObjPtr<AActor> alternative; // (Un)Morphed actors stored here. Those with the MF_UNMORPHED flag are the originals.
|
||||
TObjPtr<AActor> tracer; // Thing being chased/attacked for tracers
|
||||
TObjPtr<AActor> master; // Thing which spawned this one (prevents mutual attacks)
|
||||
double Floorclip; // value to use for floor clipping
|
||||
|
||||
int tid; // thing identifier
|
||||
int special; // special
|
||||
|
@ -1163,7 +1143,8 @@ public:
|
|||
BYTE smokecounter;
|
||||
BYTE FloatBobPhase;
|
||||
BYTE FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc)
|
||||
DWORD Translation;
|
||||
PalEntry BloodColor;
|
||||
DWORD BloodTranslation;
|
||||
|
||||
// [RH] Stuff that used to be part of an Actor Info
|
||||
FSoundIDNoInit SeeSound;
|
||||
|
|
|
@ -358,7 +358,7 @@ void DBot::WhatToGet (AActor *item)
|
|||
}
|
||||
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere)
|
||||
return;
|
||||
else if (item->IsKindOf (PClass::FindActor(NAME_Health)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina)
|
||||
else if (item->IsKindOf (PClass::FindActor(NAME_Health)) && player->mo->health >= player->mo->GetMaxHealth(true))
|
||||
return;
|
||||
|
||||
if ((dest == NULL ||
|
||||
|
|
|
@ -732,34 +732,6 @@ CCMD (dir)
|
|||
chdir (curdir);
|
||||
}
|
||||
|
||||
CCMD (fov)
|
||||
{
|
||||
player_t *player = who ? who->player : &players[consoleplayer];
|
||||
|
||||
if (argv.argc() != 2)
|
||||
{
|
||||
Printf ("fov is %g\n", player->DesiredFOV);
|
||||
return;
|
||||
}
|
||||
else if (dmflags & DF_NO_FOV)
|
||||
{
|
||||
if (consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
Net_WriteByte (DEM_FOV);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("A setting controller has disabled FOV changes.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte (DEM_MYFOV);
|
||||
}
|
||||
Net_WriteByte (clamp (atoi (argv[1]), 5, 179));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CCMD warp
|
||||
|
|
|
@ -206,6 +206,9 @@ struct FCommandBuffer
|
|||
unsigned CursorPos;
|
||||
unsigned StartPos; // First character to display
|
||||
|
||||
FString YankBuffer; // Deleted text buffer
|
||||
bool AppendToYankBuffer; // Append consecutive deletes to buffer
|
||||
|
||||
FCommandBuffer()
|
||||
{
|
||||
CursorPos = StartPos = 0;
|
||||
|
@ -278,6 +281,30 @@ struct FCommandBuffer
|
|||
StartPos = MAX(0, n);
|
||||
}
|
||||
|
||||
unsigned WordBoundaryRight()
|
||||
{
|
||||
unsigned index = CursorPos;
|
||||
while (index < Text.Len() && Text[index] == ' ') {
|
||||
index++;
|
||||
}
|
||||
while (index < Text.Len() && Text[index] != ' ') {
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
unsigned WordBoundaryLeft()
|
||||
{
|
||||
int index = CursorPos - 1;
|
||||
while (index > -1 && Text[index] == ' ') {
|
||||
index--;
|
||||
}
|
||||
while (index > -1 && Text[index] != ' ') {
|
||||
index--;
|
||||
}
|
||||
return (unsigned)index + 1;
|
||||
}
|
||||
|
||||
void CursorStart()
|
||||
{
|
||||
CursorPos = 0;
|
||||
|
@ -309,6 +336,18 @@ struct FCommandBuffer
|
|||
}
|
||||
}
|
||||
|
||||
void CursorWordLeft()
|
||||
{
|
||||
CursorPos = WordBoundaryLeft();
|
||||
MakeStartPosGood();
|
||||
}
|
||||
|
||||
void CursorWordRight()
|
||||
{
|
||||
CursorPos = WordBoundaryRight();
|
||||
MakeStartPosGood();
|
||||
}
|
||||
|
||||
void DeleteLeft()
|
||||
{
|
||||
if (CursorPos > 0)
|
||||
|
@ -328,6 +367,50 @@ struct FCommandBuffer
|
|||
}
|
||||
}
|
||||
|
||||
void DeleteWordLeft()
|
||||
{
|
||||
if (CursorPos > 0)
|
||||
{
|
||||
unsigned index = WordBoundaryLeft();
|
||||
if (AppendToYankBuffer) {
|
||||
YankBuffer = FString(&Text[index], CursorPos - index) + YankBuffer;
|
||||
} else {
|
||||
YankBuffer = FString(&Text[index], CursorPos - index);
|
||||
}
|
||||
Text.Remove(index, CursorPos - index);
|
||||
CursorPos = index;
|
||||
MakeStartPosGood();
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteLineLeft()
|
||||
{
|
||||
if (CursorPos > 0)
|
||||
{
|
||||
if (AppendToYankBuffer) {
|
||||
YankBuffer = FString(&Text[0], CursorPos) + YankBuffer;
|
||||
} else {
|
||||
YankBuffer = FString(&Text[0], CursorPos);
|
||||
}
|
||||
Text.Remove(0, CursorPos);
|
||||
CursorStart();
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteLineRight()
|
||||
{
|
||||
if (CursorPos < Text.Len())
|
||||
{
|
||||
if (AppendToYankBuffer) {
|
||||
YankBuffer += FString(&Text[CursorPos], Text.Len() - CursorPos);
|
||||
} else {
|
||||
YankBuffer = FString(&Text[CursorPos], Text.Len() - CursorPos);
|
||||
}
|
||||
Text.Truncate(CursorPos);
|
||||
CursorEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void AddChar(int character)
|
||||
{
|
||||
///FIXME: Not Unicode-aware
|
||||
|
@ -1345,6 +1428,7 @@ DEFINE_ACTION_FUNCTION(_Console, Printf)
|
|||
static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer)
|
||||
{
|
||||
int data1 = ev->data1;
|
||||
bool keepappending = false;
|
||||
|
||||
switch (ev->subtype)
|
||||
{
|
||||
|
@ -1352,8 +1436,22 @@ static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer)
|
|||
return false;
|
||||
|
||||
case EV_GUI_Char:
|
||||
if (ev->data2)
|
||||
{
|
||||
// Bash-style shortcuts
|
||||
if (data1 == 'b')
|
||||
{
|
||||
buffer.CursorWordLeft();
|
||||
break;
|
||||
}
|
||||
else if (data1 == 'f')
|
||||
{
|
||||
buffer.CursorWordRight();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Add keypress to command line
|
||||
buffer.AddChar(ev->data1);
|
||||
buffer.AddChar(data1);
|
||||
HistPos = NULL;
|
||||
TabbedLast = false;
|
||||
TabbedList = false;
|
||||
|
@ -1654,6 +1752,56 @@ static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer)
|
|||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// Bash-style shortcuts
|
||||
case 'A':
|
||||
if (ev->data3 & GKM_CTRL)
|
||||
{
|
||||
buffer.CursorStart();
|
||||
}
|
||||
break;
|
||||
case 'E':
|
||||
if (ev->data3 & GKM_CTRL)
|
||||
{
|
||||
buffer.CursorEnd();
|
||||
}
|
||||
break;
|
||||
case 'W':
|
||||
if (ev->data3 & GKM_CTRL)
|
||||
{
|
||||
buffer.DeleteWordLeft();
|
||||
keepappending = true;
|
||||
TabbedLast = false;
|
||||
TabbedList = false;
|
||||
}
|
||||
break;
|
||||
case 'U':
|
||||
if (ev->data3 & GKM_CTRL)
|
||||
{
|
||||
buffer.DeleteLineLeft();
|
||||
keepappending = true;
|
||||
TabbedLast = false;
|
||||
TabbedList = false;
|
||||
}
|
||||
break;
|
||||
case 'K':
|
||||
if (ev->data3 & GKM_CTRL)
|
||||
{
|
||||
buffer.DeleteLineRight();
|
||||
keepappending = true;
|
||||
TabbedLast = false;
|
||||
TabbedList = false;
|
||||
}
|
||||
break;
|
||||
case 'Y':
|
||||
if (ev->data3 & GKM_CTRL)
|
||||
{
|
||||
buffer.AddString(buffer.YankBuffer);
|
||||
TabbedLast = false;
|
||||
TabbedList = false;
|
||||
HistPos = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1664,6 +1812,9 @@ static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer)
|
|||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
buffer.AppendToYankBuffer = keepappending;
|
||||
|
||||
// Ensure that the cursor is always visible while typing
|
||||
CursorTicker = C_BLINKRATE;
|
||||
cursoron = 1;
|
||||
|
|
|
@ -86,6 +86,7 @@ enum
|
|||
CP_SETTHINGZ,
|
||||
CP_SETTAG,
|
||||
CP_SETTHINGFLAGS,
|
||||
CP_SETVERTEX,
|
||||
};
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
@ -345,6 +346,18 @@ void ParseCompatibility()
|
|||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
}
|
||||
else if (sc.Compare("setvertex"))
|
||||
{
|
||||
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
|
||||
CompatParams.Push(CP_SETVERTEX);
|
||||
sc.MustGetNumber();
|
||||
CompatParams.Push(sc.Number);
|
||||
sc.MustGetFloat();
|
||||
CompatParams.Push(int(sc.Float * 256)); // do not use full fixed here so that it can eventually handle larger levels
|
||||
sc.MustGetFloat();
|
||||
CompatParams.Push(int(sc.Float * 256)); // do not use full fixed here so that it can eventually handle larger levels
|
||||
flags.CompatFlags[SLOT_BCOMPAT] |= BCOMPATF_REBUILDNODES;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.UnGet();
|
||||
|
@ -600,6 +613,16 @@ void SetCompatibilityParams()
|
|||
i += 3;
|
||||
break;
|
||||
}
|
||||
case CP_SETVERTEX:
|
||||
{
|
||||
if ((unsigned)CompatParams[i + 1] < level.vertexes.Size())
|
||||
{
|
||||
level.vertexes[CompatParams[i + 1]].p.X = CompatParams[i + 2] / 256.;
|
||||
level.vertexes[CompatParams[i + 1]].p.Y = CompatParams[i + 3] / 256.;
|
||||
}
|
||||
i += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2693,6 +2693,7 @@ void D_DoomMain (void)
|
|||
// These calls from inside V_Init2 are still necessary
|
||||
C_NewModeAdjust();
|
||||
M_InitVideoModesMenu();
|
||||
Renderer->RemapVoxels();
|
||||
D_StartTitle (); // start up intro loop
|
||||
setmodeneeded = false; // This may be set to true here, but isn't needed for a restart
|
||||
}
|
||||
|
|
|
@ -2381,6 +2381,11 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
SprayDecal(players[player].mo, s);
|
||||
break;
|
||||
|
||||
case DEM_MDK:
|
||||
s = ReadString(stream);
|
||||
cht_DoMDK(&players[player], s);
|
||||
break;
|
||||
|
||||
case DEM_PAUSE:
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
|
@ -2667,13 +2672,12 @@ void Net_DoCommand (int type, BYTE **stream, int player)
|
|||
|
||||
case DEM_NETEVENT:
|
||||
{
|
||||
const char *ename = ReadString(stream);
|
||||
s = ReadString(stream);
|
||||
int argn = ReadByte(stream);
|
||||
int arg[3] = { 0, 0, 0 };
|
||||
for (int i = 0; i < 3; i++)
|
||||
arg[i] = ReadLong(stream);
|
||||
E_Console(player, ename, arg[0], arg[1], arg[2]);
|
||||
delete[] ename;
|
||||
E_Console(player, s, arg[0], arg[1], arg[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2724,7 +2728,7 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
break;
|
||||
|
||||
case DEM_NETEVENT:
|
||||
skip = strlen((char *)(*stream)) + 13;
|
||||
skip = strlen((char *)(*stream)) + 14;
|
||||
break;
|
||||
|
||||
case DEM_SUMMON2:
|
||||
|
@ -2748,6 +2752,7 @@ void Net_SkipCommand (int type, BYTE **stream)
|
|||
case DEM_SPRAY:
|
||||
case DEM_MORPHEX:
|
||||
case DEM_KILLCLASSCHEAT:
|
||||
case DEM_MDK:
|
||||
skip = strlen ((char *)(*stream)) + 1;
|
||||
break;
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ public:
|
|||
virtual bool UpdateWaterLevel (bool splash) override;
|
||||
|
||||
bool ResetAirSupply (bool playgasp = true);
|
||||
int GetMaxHealth() const;
|
||||
int GetMaxHealth(bool withupgrades = false) const;
|
||||
void TweakSpeeds (double &forwardmove, double &sidemove);
|
||||
void MorphPlayerThink ();
|
||||
void ActivateMorphWeapon ();
|
||||
|
@ -126,6 +126,8 @@ public:
|
|||
|
||||
int crouchsprite;
|
||||
int MaxHealth;
|
||||
int BonusHealth;
|
||||
|
||||
int MugShotMaxHealth;
|
||||
int RunHealth;
|
||||
int PlayerFlags;
|
||||
|
@ -160,8 +162,6 @@ public:
|
|||
FNameNoInit Face; // Doom status bar face (when used)
|
||||
FNameNoInit Portrait;
|
||||
FNameNoInit Slot[10];
|
||||
FNameNoInit InvulMode;
|
||||
FNameNoInit HealingRadiusType;
|
||||
double HexenArmor[5];
|
||||
BYTE ColorRangeStart; // Skin color range
|
||||
BYTE ColorRangeEnd;
|
||||
|
@ -530,6 +530,9 @@ public:
|
|||
DPSprite *GetPSprite(PSPLayers layer);
|
||||
|
||||
bool GetPainFlash(FName type, PalEntry *color) const;
|
||||
|
||||
// [Nash] set player FOV
|
||||
void SetFOV(float fov);
|
||||
};
|
||||
|
||||
// Bookkeeping on players - state.
|
||||
|
|
|
@ -159,7 +159,8 @@ enum EDemoCommand
|
|||
DEM_SETSLOTPNUM, // 67 Byte: player number, the rest is the same as DEM_SETSLOT
|
||||
DEM_REMOVE, // 68
|
||||
DEM_FINISHGAME, // 69
|
||||
DEM_NETEVENT // 70 String: Event name, Byte: Arg count; each arg is a 4-byte int
|
||||
DEM_NETEVENT, // 70 String: Event name, Byte: Arg count; each arg is a 4-byte int
|
||||
DEM_MDK // 71 String: Damage type
|
||||
};
|
||||
|
||||
// The following are implemented by cht_DoCheat in m_cheat.cpp
|
||||
|
|
|
@ -623,12 +623,20 @@ DEFINE_ACTION_FUNCTION(DObject, MSTime)
|
|||
|
||||
void *DObject::ScriptVar(FName field, PType *type)
|
||||
{
|
||||
auto sym = dyn_cast<PField>(GetClass()->Symbols.FindSymbol(field, true));
|
||||
auto cls = GetClass();
|
||||
auto sym = dyn_cast<PField>(cls->Symbols.FindSymbol(field, true));
|
||||
if (sym && (sym->Type == type || type == nullptr))
|
||||
{
|
||||
if (!(sym->Flags & VARF_Meta))
|
||||
{
|
||||
return (((char*)this) + sym->Offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (cls->Meta + sym->Offset);
|
||||
}
|
||||
}
|
||||
// This is only for internal use so I_Error is fine.
|
||||
I_Error("Variable %s not found in %s\n", field.GetChars(), GetClass()->TypeName.GetChars());
|
||||
I_Error("Variable %s not found in %s\n", field.GetChars(), cls->TypeName.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
class PClass;
|
||||
class PType;
|
||||
class FSerializer;
|
||||
class FSoundID;
|
||||
|
||||
class DObject;
|
||||
/*
|
||||
|
@ -483,9 +484,11 @@ public:
|
|||
// Add other types as needed.
|
||||
bool &BoolVar(FName field);
|
||||
int &IntVar(FName field);
|
||||
FSoundID &SoundVar(FName field);
|
||||
PalEntry &ColorVar(FName field);
|
||||
FName &NameVar(FName field);
|
||||
double &FloatVar(FName field);
|
||||
FString &StringVar(FName field);
|
||||
template<class T> T*& PointerVar(FName field);
|
||||
|
||||
// If you need to replace one object with another and want to
|
||||
|
|
123
src/dobjtype.cpp
123
src/dobjtype.cpp
|
@ -722,10 +722,6 @@ PBool::PBool()
|
|||
{
|
||||
mDescriptiveName = "Bool";
|
||||
MemberOnly = false;
|
||||
// Override the default max set by PInt's constructor
|
||||
PSymbolConstNumeric *maxsym = static_cast<PSymbolConstNumeric *>(Symbols.FindSymbol(NAME_Max, false));
|
||||
assert(maxsym != nullptr && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
||||
maxsym->Value = 1;
|
||||
}
|
||||
|
||||
/* PFloat *****************************************************************/
|
||||
|
@ -2311,7 +2307,7 @@ void PStruct::WriteFields(FSerializer &ar, const void *addr, const TArray<PField
|
|||
{
|
||||
const PField *field = fields[i];
|
||||
// Skip fields without or with native serialization
|
||||
if (!(field->Flags & VARF_Transient))
|
||||
if (!(field->Flags & (VARF_Transient|VARF_Meta)))
|
||||
{
|
||||
field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const BYTE *)addr + field->Offset);
|
||||
}
|
||||
|
@ -2344,6 +2340,11 @@ bool PStruct::ReadFields(FSerializer &ar, void *addr) const
|
|||
DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n",
|
||||
label, TypeName.GetChars());
|
||||
}
|
||||
else if ((static_cast<const PField *>(sym)->Flags & (VARF_Transient | VARF_Meta)))
|
||||
{
|
||||
DPrintf(DMSG_ERROR, "Symbol %s in %s is not a serializable field\n",
|
||||
label, TypeName.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
readsomething |= static_cast<const PField *>(sym)->Type->ReadValue(ar, nullptr,
|
||||
|
@ -2642,7 +2643,7 @@ static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void *
|
|||
// Don't write this part if it has no non-transient variables
|
||||
for (unsigned i = 0; i < type->Fields.Size(); ++i)
|
||||
{
|
||||
if (!(type->Fields[i]->Flags & VARF_Transient))
|
||||
if (!(type->Fields[i]->Flags & (VARF_Transient|VARF_Meta)))
|
||||
{
|
||||
// Tag this section with the class it came from in case
|
||||
// a more-derived class has variables that shadow a less-
|
||||
|
@ -2892,6 +2893,7 @@ PClass::PClass()
|
|||
bExported = false;
|
||||
bDecorateClass = false;
|
||||
ConstructNative = nullptr;
|
||||
Meta = nullptr;
|
||||
mDescriptiveName = "Class";
|
||||
|
||||
PClass::AllClasses.Push(this);
|
||||
|
@ -2910,6 +2912,11 @@ PClass::~PClass()
|
|||
M_Free(Defaults);
|
||||
Defaults = nullptr;
|
||||
}
|
||||
if (Meta != nullptr)
|
||||
{
|
||||
M_Free(Meta);
|
||||
Meta = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3047,7 +3054,7 @@ PClass *PClass::FindClass (FName zaname)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
DObject *PClass::CreateNew() const
|
||||
DObject *PClass::CreateNew()
|
||||
{
|
||||
BYTE *mem = (BYTE *)M_Malloc (Size);
|
||||
assert (mem != nullptr);
|
||||
|
@ -3064,7 +3071,7 @@ DObject *PClass::CreateNew() const
|
|||
}
|
||||
ConstructNative (mem);
|
||||
((DObject *)mem)->SetClass (const_cast<PClass *>(this));
|
||||
InitializeSpecials(mem, Defaults);
|
||||
InitializeSpecials(mem, Defaults, &PClass::SpecialInits);
|
||||
return (DObject *)mem;
|
||||
}
|
||||
|
||||
|
@ -3076,17 +3083,16 @@ DObject *PClass::CreateNew() const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::InitializeSpecials(void *addr, void *defaults) const
|
||||
void PClass::InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> PClass::*Inits)
|
||||
{
|
||||
// Once we reach a native class, we can stop going up the family tree,
|
||||
// since native classes handle initialization natively.
|
||||
if (!bRuntimeClass)
|
||||
if ((!bRuntimeClass && Inits == &PClass::SpecialInits) || ParentClass == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
assert(ParentClass != nullptr);
|
||||
ParentClass->InitializeSpecials(addr, defaults);
|
||||
for (auto tao : SpecialInits)
|
||||
ParentClass->InitializeSpecials(addr, defaults, Inits);
|
||||
for (auto tao : (this->*Inits))
|
||||
{
|
||||
tao.first->InitializeValue((char*)addr + tao.second, defaults == nullptr? nullptr : ((char*)defaults) + tao.second);
|
||||
}
|
||||
|
@ -3101,7 +3107,7 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::DestroySpecials(void *addr) const
|
||||
void PClass::DestroySpecials(void *addr)
|
||||
{
|
||||
// Once we reach a native class, we can stop going up the family tree,
|
||||
// since native classes handle deinitialization natively.
|
||||
|
@ -3160,7 +3166,6 @@ void PClass::InitializeDefaults()
|
|||
optr->ObjNext = nullptr;
|
||||
optr->SetClass(this);
|
||||
|
||||
|
||||
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
|
||||
if (ParentClass->Defaults != nullptr)
|
||||
{
|
||||
|
@ -3174,21 +3179,53 @@ void PClass::InitializeDefaults()
|
|||
{
|
||||
memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject));
|
||||
}
|
||||
|
||||
assert(MetaSize >= ParentClass->MetaSize);
|
||||
if (MetaSize != 0)
|
||||
{
|
||||
Meta = (BYTE*)M_Malloc(MetaSize);
|
||||
|
||||
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
|
||||
if (ParentClass->Meta != nullptr)
|
||||
{
|
||||
memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize);
|
||||
if (MetaSize > ParentClass->MetaSize)
|
||||
{
|
||||
memset(Meta + ParentClass->MetaSize, 0, MetaSize - ParentClass->MetaSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(Meta, 0, MetaSize);
|
||||
}
|
||||
|
||||
if (MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize);
|
||||
else memset(Meta, 0, MetaSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (bRuntimeClass)
|
||||
{
|
||||
// Copy parent values from the parent defaults.
|
||||
assert(ParentClass != nullptr);
|
||||
if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults);
|
||||
if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits);
|
||||
if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits);
|
||||
for (const PField *field : Fields)
|
||||
{
|
||||
if (!(field->Flags & VARF_Native))
|
||||
if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta))
|
||||
{
|
||||
field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits);
|
||||
for (const PField *field : Fields)
|
||||
{
|
||||
if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta))
|
||||
{
|
||||
field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3248,6 +3285,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
|
|||
type->bRuntimeClass = true;
|
||||
Derive(type, name);
|
||||
type->Size = size;
|
||||
type->MetaSize = MetaSize;
|
||||
if (size != TentativeClass)
|
||||
{
|
||||
type->InitializeDefaults();
|
||||
|
@ -3264,6 +3302,39 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
|
|||
return type;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStruct :: AddField
|
||||
//
|
||||
// Appends a new metadata field to the end of a struct. Returns either the new field
|
||||
// or nullptr if a symbol by that name already exists.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PField *PClass::AddMetaField(FName name, PType *type, DWORD flags)
|
||||
{
|
||||
PField *field = new PField(name, type, flags);
|
||||
|
||||
// The new field is added to the end of this struct, alignment permitting.
|
||||
field->Offset = (MetaSize + (type->Align - 1)) & ~(type->Align - 1);
|
||||
|
||||
// Enlarge this struct to enclose the new field.
|
||||
MetaSize = unsigned(field->Offset + type->Size);
|
||||
|
||||
// This struct's alignment is the same as the largest alignment of any of
|
||||
// its fields.
|
||||
Align = MAX(Align, type->Align);
|
||||
|
||||
if (Symbols.AddSymbol(field) == nullptr)
|
||||
{ // name is already in use
|
||||
field->Destroy();
|
||||
return nullptr;
|
||||
}
|
||||
Fields.Push(field);
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClass :: AddField
|
||||
|
@ -3271,6 +3342,8 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
|
|||
//==========================================================================
|
||||
|
||||
PField *PClass::AddField(FName name, PType *type, DWORD flags)
|
||||
{
|
||||
if (!(flags & VARF_Meta))
|
||||
{
|
||||
unsigned oldsize = Size;
|
||||
PField *field = Super::AddField(name, type, flags);
|
||||
|
@ -3285,6 +3358,22 @@ PField *PClass::AddField(FName name, PType *type, DWORD flags)
|
|||
}
|
||||
return field;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned oldsize = MetaSize;
|
||||
PField *field = AddMetaField(name, type, flags);
|
||||
|
||||
// Only initialize the defaults if they have already been created.
|
||||
// For ZScript this is not the case, it will first define all fields before
|
||||
// setting up any defaults for any class.
|
||||
if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr)
|
||||
{
|
||||
Meta = (BYTE *)M_Realloc(Meta, MetaSize);
|
||||
memset(Meta + oldsize, 0, MetaSize - oldsize);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
@ -557,12 +557,13 @@ enum
|
|||
class PClass : public PNativeStruct
|
||||
{
|
||||
DECLARE_CLASS(PClass, PNativeStruct);
|
||||
protected:
|
||||
// We unravel _WITH_META here just as we did for PType.
|
||||
TArray<FTypeAndOffset> SpecialInits;
|
||||
protected:
|
||||
TArray<FTypeAndOffset> MetaInits;
|
||||
void Derive(PClass *newclass, FName name);
|
||||
void InitializeSpecials(void *addr, void *defaults) const;
|
||||
void InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> PClass::*Inits);
|
||||
void SetSuper();
|
||||
PField *AddMetaField(FName name, PType *type, DWORD flags);
|
||||
public:
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
void WriteAllFields(FSerializer &ar, const void *addr) const;
|
||||
|
@ -577,11 +578,14 @@ public:
|
|||
static void StaticBootstrap();
|
||||
|
||||
// Per-class information -------------------------------------
|
||||
TArray<FTypeAndOffset> SpecialInits;
|
||||
PClass *ParentClass; // the class this class derives from
|
||||
const size_t *Pointers; // object pointers defined by this class *only*
|
||||
const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default
|
||||
const size_t *ArrayPointers; // dynamic arrays containing object pointers.
|
||||
BYTE *Defaults;
|
||||
BYTE *Meta; // Per-class static script data
|
||||
unsigned MetaSize;
|
||||
bool bRuntimeClass; // class was defined at run-time, not compile-time
|
||||
bool bExported; // This type has been declared in a script
|
||||
bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility
|
||||
|
@ -593,13 +597,14 @@ public:
|
|||
PClass();
|
||||
~PClass();
|
||||
void InsertIntoHash();
|
||||
DObject *CreateNew() const;
|
||||
DObject *CreateNew();
|
||||
PClass *CreateDerivedClass(FName name, unsigned int size);
|
||||
PField *AddField(FName name, PType *type, DWORD flags=0) override;
|
||||
void InitializeActorInfo();
|
||||
void BuildFlatPointers();
|
||||
void BuildArrayPointers();
|
||||
void DestroySpecials(void *addr) const;
|
||||
void InitMeta();
|
||||
void DestroySpecials(void *addr);
|
||||
const PClass *NativeClass() const;
|
||||
|
||||
// Returns true if this type is an ancestor of (or same as) the passed type.
|
||||
|
@ -723,6 +728,11 @@ inline int &DObject::IntVar(FName field)
|
|||
return *(int*)ScriptVar(field, TypeSInt32);
|
||||
}
|
||||
|
||||
inline FSoundID &DObject::SoundVar(FName field)
|
||||
{
|
||||
return *(FSoundID*)ScriptVar(field, TypeSound);
|
||||
}
|
||||
|
||||
inline PalEntry &DObject::ColorVar(FName field)
|
||||
{
|
||||
return *(PalEntry*)ScriptVar(field, TypeColor);
|
||||
|
@ -738,6 +748,11 @@ inline double &DObject::FloatVar(FName field)
|
|||
return *(double*)ScriptVar(field, TypeFloat64);
|
||||
}
|
||||
|
||||
inline FString &DObject::StringVar(FName field)
|
||||
{
|
||||
return *(FString*)ScriptVar(field, TypeString);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T *&DObject::PointerVar(FName field)
|
||||
{
|
||||
|
|
|
@ -360,7 +360,7 @@ struct FMapThing
|
|||
double Alpha;
|
||||
DWORD fillcolor;
|
||||
DVector2 Scale;
|
||||
int health;
|
||||
double Health;
|
||||
int score;
|
||||
short pitch;
|
||||
short roll;
|
||||
|
|
|
@ -50,8 +50,6 @@ DEFINE_FIELD(AInventory, DropTime)
|
|||
DEFINE_FIELD(AInventory, SpawnPointClass)
|
||||
DEFINE_FIELD(AInventory, PickupFlash)
|
||||
DEFINE_FIELD(AInventory, PickupSound)
|
||||
DEFINE_FIELD(AInventory, GiveQuest)
|
||||
DEFINE_FIELD(PClassActor, PickupMsg)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -115,8 +113,7 @@ void AInventory::Serialize(FSerializer &arc)
|
|||
("icon", Icon, def->Icon)
|
||||
("pickupsound", PickupSound, def->PickupSound)
|
||||
("spawnpointclass", SpawnPointClass, def->SpawnPointClass)
|
||||
("droptime", DropTime, def->DropTime)
|
||||
("givequest", GiveQuest, def->GiveQuest);
|
||||
("droptime", DropTime, def->DropTime);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -17,7 +17,7 @@ struct visstyle_t;
|
|||
|
||||
// A pickup is anything the player can pickup (i.e. weapons, ammo, powerups, etc)
|
||||
|
||||
enum
|
||||
enum ItemFlag
|
||||
{
|
||||
IF_ACTIVATABLE = 1<<0, // can be activated
|
||||
IF_ACTIVATED = 1<<1, // is currently activated
|
||||
|
@ -46,8 +46,14 @@ enum
|
|||
IF_TRANSFER = 1<<24, // All inventory items that the inventory item contains is also transfered to the pickuper
|
||||
IF_NOTELEPORTFREEZE = 1<<25, // does not 'freeze' the player right after teleporting.
|
||||
IF_NOSCREENBLINK = 1<<26, // Does not blink the screen overlay when expiring.
|
||||
IF_ISHEALTH = 1<<27, // for the DM flag so that it can recognize items that are not obviously health givers.
|
||||
IF_ISARMOR = 1<<28, // for the DM flag so that it can recognize items that are not obviously armor givers.
|
||||
};
|
||||
|
||||
typedef TFlags<ItemFlag> InvFlags;
|
||||
//typedef TFlags<ItemFlag2> ItemFlags2;
|
||||
DEFINE_TFLAGS_OPERATORS(InvFlags)
|
||||
//DEFINE_TFLAGS_OPERATORS(ItemFlags2)
|
||||
|
||||
class AInventory : public AActor
|
||||
{
|
||||
|
@ -87,10 +93,9 @@ public:
|
|||
FTextureID Icon; // Icon to show on status bar or HUD
|
||||
int DropTime; // Countdown after dropping
|
||||
PClassActor *SpawnPointClass; // For respawning like Heretic's mace
|
||||
int GiveQuest; // Optionally give one of the quest items.
|
||||
FTextureID AltHUDIcon;
|
||||
|
||||
DWORD ItemFlags;
|
||||
InvFlags ItemFlags;
|
||||
PClassActor *PickupFlash; // actor to spawn as pickup flash
|
||||
|
||||
FSoundIDNoInit PickupSound;
|
||||
|
|
|
@ -1624,6 +1624,7 @@ void G_UnSnapshotLevel (bool hubLoad)
|
|||
}
|
||||
}
|
||||
}
|
||||
arc.Close();
|
||||
}
|
||||
// No reason to keep the snapshot around once the level's been entered.
|
||||
level.info->Snapshot.Clean();
|
||||
|
|
|
@ -2744,7 +2744,7 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
max = 0;
|
||||
}
|
||||
else //default to the class's health
|
||||
max = statusBar->CPlayer->mo->GetMaxHealth() + statusBar->CPlayer->mo->stamina;
|
||||
max = statusBar->CPlayer->mo->GetMaxHealth(true);
|
||||
break;
|
||||
case ARMOR:
|
||||
value = statusBar->armor != NULL ? statusBar->armor->Amount : 0;
|
||||
|
@ -3251,7 +3251,7 @@ class CommandDrawGem : public SBarInfoCommand
|
|||
void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged)
|
||||
{
|
||||
goalValue = armor ? (statusBar->armor ? statusBar->armor->Amount : 0) : statusBar->CPlayer->mo->health;
|
||||
int max = armor ? 100 : statusBar->CPlayer->mo->GetMaxHealth() + statusBar->CPlayer->mo->stamina;
|
||||
int max = armor ? 100 : statusBar->CPlayer->mo->GetMaxHealth(true);
|
||||
if(max != 0 && goalValue > 0)
|
||||
{
|
||||
goalValue = (goalValue*100)/max;
|
||||
|
|
|
@ -56,6 +56,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mBackButton)
|
|||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenMapNameFont)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenEnteringFont)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenFinishedFont)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gibfactor)
|
||||
|
||||
|
||||
const char *GameNames[17] =
|
||||
|
|
|
@ -204,7 +204,8 @@ void ADynamicLight::Activate(AActor *activator)
|
|||
float pulseTime = specialf1 / TICRATE;
|
||||
|
||||
m_lastUpdate = level.maptime;
|
||||
m_cycler.SetParams(float(args[LIGHT_SECONDARY_INTENSITY]), float(args[LIGHT_INTENSITY]), pulseTime);
|
||||
if (!swapped) m_cycler.SetParams(float(args[LIGHT_SECONDARY_INTENSITY]), float(args[LIGHT_INTENSITY]), pulseTime);
|
||||
else m_cycler.SetParams(float(args[LIGHT_INTENSITY]), float(args[LIGHT_SECONDARY_INTENSITY]), pulseTime);
|
||||
m_cycler.ShouldCycle(true);
|
||||
m_cycler.SetCycleType(CYCLE_Sin);
|
||||
m_currentRadius = m_cycler.GetVal();
|
||||
|
|
|
@ -135,6 +135,16 @@ public:
|
|||
void SetDontLightSelf(bool add) { m_dontlightself = add; }
|
||||
void SetAttenuate(bool on) { m_attenuate = on; }
|
||||
void SetHalo(bool halo) { m_halo = halo; }
|
||||
|
||||
void OrderIntensities()
|
||||
{
|
||||
if (m_Args[LIGHT_INTENSITY] > m_Args[LIGHT_SECONDARY_INTENSITY])
|
||||
{
|
||||
std::swap(m_Args[LIGHT_INTENSITY], m_Args[LIGHT_SECONDARY_INTENSITY]);
|
||||
m_swapped = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
FName m_Name;
|
||||
int m_Args[5];
|
||||
|
@ -143,6 +153,7 @@ protected:
|
|||
ELightType m_type;
|
||||
int8_t m_attenuate;
|
||||
bool m_subtractive, m_additive, m_halo, m_dontlightself;
|
||||
bool m_swapped = false;
|
||||
};
|
||||
|
||||
TArray<FLightDefaults *> LightDefaults;
|
||||
|
@ -178,8 +189,8 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const
|
|||
light->SetOffset(m_Pos);
|
||||
light->halo = m_halo;
|
||||
for (int a = 0; a < 3; a++) light->args[a] = clamp<int>((int)(m_Args[a]), 0, 255);
|
||||
light->args[LIGHT_INTENSITY] = int(m_Args[LIGHT_INTENSITY]);
|
||||
light->args[LIGHT_SECONDARY_INTENSITY] = int(m_Args[LIGHT_SECONDARY_INTENSITY]);
|
||||
light->args[LIGHT_INTENSITY] = m_Args[LIGHT_INTENSITY];
|
||||
light->args[LIGHT_SECONDARY_INTENSITY] = m_Args[LIGHT_SECONDARY_INTENSITY];
|
||||
light->flags4 &= ~(MF4_ADDITIVE | MF4_SUBTRACTIVE | MF4_DONTLIGHTSELF);
|
||||
if (m_subtractive) light->flags4 |= MF4_SUBTRACTIVE;
|
||||
if (m_additive) light->flags4 |= MF4_ADDITIVE;
|
||||
|
@ -190,11 +201,13 @@ void FLightDefaults::ApplyProperties(ADynamicLight * light) const
|
|||
float pulseTime = float(m_Param / TICRATE);
|
||||
|
||||
light->m_lastUpdate = level.maptime;
|
||||
light->m_cycler.SetParams(float(light->args[LIGHT_SECONDARY_INTENSITY]), float(light->args[LIGHT_INTENSITY]), pulseTime, oldtype == PulseLight);
|
||||
if (m_swapped) light->m_cycler.SetParams(float(light->args[LIGHT_SECONDARY_INTENSITY]), float(light->args[LIGHT_INTENSITY]), pulseTime, oldtype == PulseLight);
|
||||
else light->m_cycler.SetParams(float(light->args[LIGHT_INTENSITY]), float(light->args[LIGHT_SECONDARY_INTENSITY]), pulseTime, oldtype == PulseLight);
|
||||
light->m_cycler.ShouldCycle(true);
|
||||
light->m_cycler.SetCycleType(CYCLE_Sin);
|
||||
light->m_currentRadius = light->m_cycler.GetVal();
|
||||
if (light->m_currentRadius <= 0) light->m_currentRadius = 1;
|
||||
light->swapped = m_swapped;
|
||||
}
|
||||
|
||||
switch (m_attenuate)
|
||||
|
@ -474,13 +487,7 @@ void gl_ParsePulseLight(FScanner &sc)
|
|||
sc.ScriptError("Unknown tag: %s\n", sc.String);
|
||||
}
|
||||
}
|
||||
if (defaults->GetArg(LIGHT_INTENSITY) > defaults->GetArg(LIGHT_SECONDARY_INTENSITY))
|
||||
{
|
||||
auto i = defaults->GetArg(LIGHT_INTENSITY);
|
||||
auto j = defaults->GetArg(LIGHT_SECONDARY_INTENSITY);
|
||||
defaults->SetArg(LIGHT_INTENSITY, j);
|
||||
defaults->SetArg(LIGHT_SECONDARY_INTENSITY, i);
|
||||
}
|
||||
defaults->OrderIntensities();
|
||||
|
||||
gl_AddLightDefaults(defaults);
|
||||
}
|
||||
|
@ -564,6 +571,7 @@ void gl_ParseFlickerLight(FScanner &sc)
|
|||
sc.ScriptError("Unknown tag: %s\n", sc.String);
|
||||
}
|
||||
}
|
||||
defaults->OrderIntensities();
|
||||
gl_AddLightDefaults(defaults);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -141,6 +141,7 @@ public:
|
|||
bool halo;
|
||||
BYTE color2[3];
|
||||
bool visibletoplayer;
|
||||
bool swapped;
|
||||
int bufferindex;
|
||||
|
||||
|
||||
|
|
|
@ -665,7 +665,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
|
|||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
|
||||
// Don't waste time projecting sprites that are definitely not visible.
|
||||
if ((thing->sprite == 0 && !isPicnumOverride) || !thing->IsVisibleToPlayer() || !thing->IsInsideVisibleAngles())
|
||||
if ((thing->sprite == 0 && !isPicnumOverride) || !thing->IsVisibleToPlayer() || ((thing->renderflags & RF_MASKROTATION) && !thing->IsInsideVisibleAngles()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
38
src/info.cpp
38
src/info.cpp
|
@ -251,20 +251,7 @@ PClassActor::PClassActor()
|
|||
DamageFactors = NULL;
|
||||
PainChances = NULL;
|
||||
|
||||
DeathHeight = -1;
|
||||
BurnHeight = -1;
|
||||
GibHealth = INT_MIN;
|
||||
WoundHealth = 6;
|
||||
FastSpeed = -1.;
|
||||
RDFactor = 1.;
|
||||
CameraHeight = INT_MIN;
|
||||
|
||||
DropItems = NULL;
|
||||
|
||||
DontHurtShooter = false;
|
||||
ExplosionRadius = -1;
|
||||
MeleeDamage = 0;
|
||||
|
||||
// Record this in the master list.
|
||||
AllActorClasses.Push(this);
|
||||
}
|
||||
|
@ -308,32 +295,10 @@ void PClassActor::DeriveData(PClass *newclass)
|
|||
PClassActor *newa = static_cast<PClassActor *>(newclass);
|
||||
|
||||
newa->DefaultStateUsage = DefaultStateUsage;
|
||||
newa->Obituary = Obituary;
|
||||
newa->HitObituary = HitObituary;
|
||||
newa->DeathHeight = DeathHeight;
|
||||
newa->BurnHeight = BurnHeight;
|
||||
newa->BloodColor = BloodColor;
|
||||
newa->GibHealth = GibHealth;
|
||||
newa->WoundHealth = WoundHealth;
|
||||
newa->FastSpeed = FastSpeed;
|
||||
newa->RDFactor = RDFactor;
|
||||
newa->CameraHeight = CameraHeight;
|
||||
newa->HowlSound = HowlSound;
|
||||
newa->BloodType = BloodType;
|
||||
newa->BloodType2 = BloodType2;
|
||||
newa->BloodType3 = BloodType3;
|
||||
newa->distancecheck = distancecheck;
|
||||
|
||||
newa->DropItems = DropItems;
|
||||
|
||||
newa->DontHurtShooter = DontHurtShooter;
|
||||
newa->ExplosionRadius = ExplosionRadius;
|
||||
newa->ExplosionDamage = ExplosionDamage;
|
||||
newa->MeleeDamage = MeleeDamage;
|
||||
newa->MeleeSound = MeleeSound;
|
||||
newa->MissileName = MissileName;
|
||||
newa->MissileHeight = MissileHeight;
|
||||
|
||||
newa->VisibleToPlayerClass = VisibleToPlayerClass;
|
||||
|
||||
if (DamageFactors != NULL)
|
||||
|
@ -350,7 +315,6 @@ void PClassActor::DeriveData(PClass *newclass)
|
|||
}
|
||||
|
||||
// Inventory stuff
|
||||
newa->PickupMsg = PickupMsg;
|
||||
newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass;
|
||||
newa->RestrictedToPlayerClass = RestrictedToPlayerClass;
|
||||
|
||||
|
@ -866,7 +830,7 @@ void FMapInfoParser::ParseDamageDefinition()
|
|||
dtd.DefaultFactor = sc.Float;
|
||||
if (dtd.DefaultFactor == 0) dtd.ReplaceFactor = true;
|
||||
}
|
||||
if (sc.Compare("OBITUARY"))
|
||||
else if (sc.Compare("OBITUARY"))
|
||||
{
|
||||
sc.MustGetStringName("=");
|
||||
sc.MustGetString();
|
||||
|
|
25
src/info.h
25
src/info.h
|
@ -290,36 +290,11 @@ public:
|
|||
|
||||
TArray<PClassActor *> VisibleToPlayerClass;
|
||||
|
||||
FString Obituary; // Player was killed by this actor
|
||||
FString HitObituary; // Player was killed by this actor in melee
|
||||
double DeathHeight; // Height on normal death
|
||||
double BurnHeight; // Height on burning death
|
||||
PalEntry BloodColor; // Colorized blood
|
||||
int GibHealth; // Negative health below which this monster dies an extreme death
|
||||
int WoundHealth; // Health needed to enter wound state
|
||||
double FastSpeed; // speed in fast mode
|
||||
double RDFactor; // Radius damage factor
|
||||
double CameraHeight; // Height of camera when used as such
|
||||
FSoundID HowlSound; // Sound being played when electrocuted or poisoned
|
||||
FName BloodType; // Blood replacement type
|
||||
FName BloodType2; // Bloopsplatter replacement type
|
||||
FName BloodType3; // AxeBlood replacement type
|
||||
|
||||
FDropItem *DropItems;
|
||||
FString SourceLumpName;
|
||||
FIntCVar *distancecheck;
|
||||
|
||||
// Old Decorate compatibility stuff
|
||||
bool DontHurtShooter;
|
||||
int ExplosionRadius;
|
||||
int ExplosionDamage;
|
||||
int MeleeDamage;
|
||||
FSoundID MeleeSound;
|
||||
FName MissileName;
|
||||
double MissileHeight;
|
||||
|
||||
// These are only valid for inventory items.
|
||||
FString PickupMsg;
|
||||
TArray<PClassActor *> RestrictedToPlayerClass;
|
||||
TArray<PClassActor *> ForbiddenToPlayerClass;
|
||||
|
||||
|
|
|
@ -58,15 +58,15 @@ enum EScrollDir
|
|||
};
|
||||
|
||||
// actions that don't create objects
|
||||
#define WIPER_ID ((const PClass*)intptr_t(-1))
|
||||
#define TITLE_ID ((const PClass*)intptr_t(-2))
|
||||
#define WIPER_ID ((PClass*)intptr_t(-1))
|
||||
#define TITLE_ID ((PClass*)intptr_t(-2))
|
||||
|
||||
//==========================================================================
|
||||
|
||||
struct FIntermissionAction
|
||||
{
|
||||
int mSize;
|
||||
const PClass *mClass;
|
||||
PClass *mClass;
|
||||
FString mMusic;
|
||||
int mMusicOrder;
|
||||
int mCdTrack;
|
||||
|
|
|
@ -56,6 +56,22 @@
|
|||
// writes some bytes to the network data stream, and the network code
|
||||
// later calls us.
|
||||
|
||||
void cht_DoMDK(player_t *player, const char *mod)
|
||||
{
|
||||
if (player->mo == NULL)
|
||||
{
|
||||
Printf("What do you want to kill outside of a game?\n");
|
||||
}
|
||||
else if (!deathmatch)
|
||||
{
|
||||
// Don't allow this in deathmatch even with cheats enabled, because it's
|
||||
// a very very cheap kill.
|
||||
P_LineAttack(player->mo, player->mo->Angles.Yaw, PLAYERMISSILERANGE,
|
||||
P_AimLineAttack(player->mo, player->mo->Angles.Yaw, PLAYERMISSILERANGE), TELEFRAG_DAMAGE,
|
||||
mod, NAME_BulletPuff);
|
||||
}
|
||||
}
|
||||
|
||||
void cht_DoCheat (player_t *player, int cheat)
|
||||
{
|
||||
static const char * const BeholdPowers[9] =
|
||||
|
@ -672,6 +688,7 @@ CCMD (mdk)
|
|||
if (CheckCheatmode ())
|
||||
return;
|
||||
|
||||
Net_WriteByte (DEM_GENERICCHEAT);
|
||||
Net_WriteByte (CHT_MDK);
|
||||
const char *name = argv.argc() > 1 ? argv[1] : "";
|
||||
Net_WriteByte (DEM_MDK);
|
||||
Net_WriteString(name);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
class player_t;
|
||||
class PClassActor;
|
||||
|
||||
void cht_DoMDK(player_t *player, const char *mod);
|
||||
void cht_DoCheat (player_t *player, int cheat);
|
||||
void cht_Give (player_t *player, const char *item, int amount=1);
|
||||
void cht_Take (player_t *player, const char *item, int amount=1);
|
||||
|
|
|
@ -472,7 +472,7 @@ void M_SetMenu(FName menu, int param)
|
|||
}
|
||||
else
|
||||
{
|
||||
const PClass *menuclass = PClass::FindClass(menu);
|
||||
PClass *menuclass = PClass::FindClass(menu);
|
||||
if (menuclass != nullptr)
|
||||
{
|
||||
if (menuclass->IsDescendantOf("GenericMenu"))
|
||||
|
|
|
@ -867,6 +867,25 @@ static void ParseOptionMenu(FScanner &sc)
|
|||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static void ParseAddOptionMenu(FScanner &sc)
|
||||
{
|
||||
sc.MustGetString();
|
||||
|
||||
DMenuDescriptor **pOld = MenuDescriptors.CheckKey(sc.String);
|
||||
if (pOld == nullptr || *pOld == nullptr || !(*pOld)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)))
|
||||
{
|
||||
sc.ScriptError("%s is not an option menu that can be extended", sc.String);
|
||||
}
|
||||
ParseOptionMenuBody(sc, (DOptionMenuDescriptor*)(*pOld));
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
|
@ -931,6 +950,10 @@ void M_ParseMenuDefs()
|
|||
{
|
||||
ParseOptionMenu(sc);
|
||||
}
|
||||
else if (sc.Compare("ADDOPTIONMENU"))
|
||||
{
|
||||
ParseAddOptionMenu(sc);
|
||||
}
|
||||
else if (sc.Compare("DEFAULTOPTIONMENU"))
|
||||
{
|
||||
ParseOptionMenuBody(sc, DefaultOptionMenuSettings);
|
||||
|
|
|
@ -46,7 +46,6 @@ xx(Shadow)
|
|||
xx(Subtract)
|
||||
xx(Subtractive)
|
||||
xx(FillColor)
|
||||
xx(HealthFactor)
|
||||
|
||||
// Healingradius types
|
||||
xx(Mana)
|
||||
|
@ -392,12 +391,19 @@ xx(Radius)
|
|||
xx(ReactionTime)
|
||||
xx(MeleeRange)
|
||||
xx(Speed)
|
||||
xx(FastSpeed)
|
||||
xx(HowlSound)
|
||||
xx(Clamp)
|
||||
xx(VisibleStartAngle)
|
||||
xx(VisibleStartPitch)
|
||||
xx(VisibleEndAngle)
|
||||
xx(VisibleEndPitch)
|
||||
xx(Format)
|
||||
xx(PickupMsg)
|
||||
xx(Respawnable)
|
||||
xx(ExplosionDamage)
|
||||
xx(ExplosionRadius)
|
||||
xx(DontHurtShooter)
|
||||
|
||||
// Various actor names which are used internally
|
||||
xx(MapSpot)
|
||||
|
|
|
@ -1330,7 +1330,7 @@ static int CheckInventory (AActor *activator, const char *type, bool max)
|
|||
if (max)
|
||||
{
|
||||
if (activator->IsKindOf (RUNTIME_CLASS (APlayerPawn)))
|
||||
return static_cast<APlayerPawn *>(activator)->MaxHealth;
|
||||
return static_cast<APlayerPawn *>(activator)->GetMaxHealth();
|
||||
else
|
||||
return activator->SpawnHealth();
|
||||
}
|
||||
|
@ -3939,7 +3939,7 @@ int DLevelScript::GetActorProperty (int tid, int property)
|
|||
case APROP_Dormant: return !!(actor->flags2 & MF2_DORMANT);
|
||||
case APROP_SpawnHealth: if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn)))
|
||||
{
|
||||
return static_cast<APlayerPawn *>(actor)->MaxHealth;
|
||||
return static_cast<APlayerPawn *>(actor)->GetMaxHealth();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4232,7 +4232,7 @@ enum
|
|||
SOUND_Howl,
|
||||
};
|
||||
|
||||
static FSoundID GetActorSound(const AActor *actor, int soundtype)
|
||||
static FSoundID GetActorSound(AActor *actor, int soundtype)
|
||||
{
|
||||
switch (soundtype)
|
||||
{
|
||||
|
@ -4245,7 +4245,7 @@ static FSoundID GetActorSound(const AActor *actor, int soundtype)
|
|||
case SOUND_Bounce: return actor->BounceSound;
|
||||
case SOUND_WallBounce: return actor->WallBounceSound;
|
||||
case SOUND_CrushPain: return actor->CrushPainSound;
|
||||
case SOUND_Howl: return actor->GetClass()->HowlSound;
|
||||
case SOUND_Howl: return actor->SoundVar(NAME_HowlSound);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
@ -4367,6 +4367,10 @@ enum EACSFunctions
|
|||
ACSF_SetTranslation,
|
||||
ACSF_GetActorFloorTexture,
|
||||
ACSF_GetActorFloorTerrain,
|
||||
ACSF_StrArg,
|
||||
ACSF_Floor,
|
||||
ACSF_Round,
|
||||
ACSF_Ceil,
|
||||
|
||||
|
||||
// OpenGL stuff
|
||||
|
@ -6087,7 +6091,17 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
|||
break;
|
||||
}
|
||||
|
||||
case ACSF_StrArg:
|
||||
return -FName(FBehavior::StaticLookupString(args[0]));
|
||||
|
||||
case ACSF_Floor:
|
||||
return args[0] & ~0xffff;
|
||||
|
||||
case ACSF_Ceil:
|
||||
return (args[0] & ~0xffff) + 0x10000;
|
||||
|
||||
case ACSF_Round:
|
||||
return (args[0] + 32768) & ~0xffff;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -86,7 +86,6 @@ AActor *SingleActorFromTID(int tid, AActor *defactor);
|
|||
|
||||
|
||||
static FRandom pr_camissile ("CustomActorfire");
|
||||
static FRandom pr_camelee ("CustomMelee");
|
||||
static FRandom pr_cabullet ("CustomBullet");
|
||||
static FRandom pr_cajump ("CustomJump");
|
||||
static FRandom pr_cwbullet ("CustomWpBullet");
|
||||
|
@ -439,22 +438,6 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpawnHealth)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// GetGibHealth
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_ACTION_FUNCTION(AActor, GetGibHealth)
|
||||
{
|
||||
if (numret > 0)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
ret->SetInt(self->GetGibHealth());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// GetSpriteAngle
|
||||
|
@ -924,86 +907,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_CopyFriendliness)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Customizable attack functions which use actor parameters.
|
||||
//
|
||||
//==========================================================================
|
||||
static void DoAttack (AActor *self, bool domelee, bool domissile,
|
||||
int MeleeDamage, FSoundID MeleeSound, PClassActor *MissileType,double MissileHeight)
|
||||
{
|
||||
if (self->target == NULL) return;
|
||||
|
||||
A_FaceTarget (self);
|
||||
if (domelee && MeleeDamage>0 && self->CheckMeleeRange ())
|
||||
{
|
||||
int damage = pr_camelee.HitDice(MeleeDamage);
|
||||
if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM);
|
||||
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
|
||||
}
|
||||
else if (domissile && MissileType != NULL)
|
||||
{
|
||||
// This seemingly senseless code is needed for proper aiming.
|
||||
double add = MissileHeight + self->GetBobOffset() - 32;
|
||||
self->AddZ(add);
|
||||
AActor *missile = P_SpawnMissileXYZ (self->PosPlusZ(32.), self, self->target, MissileType, false);
|
||||
self->AddZ(-add);
|
||||
|
||||
if (missile)
|
||||
{
|
||||
// automatic handling of seeker missiles
|
||||
if (missile->flags2&MF2_SEEKERMISSILE)
|
||||
{
|
||||
missile->tracer=self->target;
|
||||
}
|
||||
P_CheckMissileSpawn(missile, self->radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_MeleeAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
int MeleeDamage = self->GetClass()->MeleeDamage;
|
||||
FSoundID MeleeSound = self->GetClass()->MeleeSound;
|
||||
DoAttack(self, true, false, MeleeDamage, MeleeSound, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_MissileAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName);
|
||||
DoAttack(self, false, true, 0, 0, MissileType, self->GetClass()->MissileHeight);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_ComboAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
int MeleeDamage = self->GetClass()->MeleeDamage;
|
||||
FSoundID MeleeSound = self->GetClass()->MeleeSound;
|
||||
PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName);
|
||||
DoAttack(self, true, true, MeleeDamage, MeleeSound, MissileType, self->GetClass()->MissileHeight);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_BasicAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT (melee_damage);
|
||||
PARAM_SOUND (melee_sound);
|
||||
PARAM_CLASS (missile_type, AActor);
|
||||
PARAM_FLOAT (missile_height);
|
||||
|
||||
if (missile_type != NULL)
|
||||
{
|
||||
DoAttack(self, true, true, melee_damage, melee_sound, missile_type, missile_height);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Custom sound functions.
|
||||
|
@ -1261,9 +1164,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_Explode)
|
|||
|
||||
if (damage < 0) // get parameters from metadata
|
||||
{
|
||||
damage = self->GetClass()->ExplosionDamage;
|
||||
distance = self->GetClass()->ExplosionRadius;
|
||||
flags = !self->GetClass()->DontHurtShooter;
|
||||
damage = self->IntVar(NAME_ExplosionDamage);
|
||||
distance = self->IntVar(NAME_ExplosionRadius);
|
||||
flags = !self->BoolVar(NAME_DontHurtShooter);
|
||||
alert = false;
|
||||
}
|
||||
if (distance <= 0) distance = damage;
|
||||
|
@ -2677,8 +2580,7 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags)
|
|||
else if (flags & SIXF_USEBLOODCOLOR)
|
||||
{
|
||||
// [XA] Use the spawning actor's BloodColor to translate the newly-spawned object.
|
||||
PalEntry bloodcolor = self->GetBloodColor();
|
||||
mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
|
||||
mo->Translation = self->BloodTranslation;
|
||||
}
|
||||
}
|
||||
if (flags & SIXF_TRANSFERPOINTERS)
|
||||
|
|
|
@ -583,3 +583,18 @@ bool EV_CeilingCrushStop (int tag, bool remove)
|
|||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
bool EV_StopCeiling(int tag)
|
||||
{
|
||||
FSectorTagIterator it(tag);
|
||||
while (int sec = it.Next())
|
||||
{
|
||||
if (level.sectors[sec].ceilingdata)
|
||||
{
|
||||
SN_StopSequence(&level.sectors[sec], CHAN_CEILING);
|
||||
level.sectors[sec].ceilingdata->Destroy();
|
||||
level.sectors[sec].ceilingdata = nullptr;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3218,13 +3218,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ActiveSound)
|
|||
//---------------------------------------------------------------------------
|
||||
void ModifyDropAmount(AInventory *inv, int dropamount)
|
||||
{
|
||||
int flagmask = IF_IGNORESKILL;
|
||||
auto flagmask = IF_IGNORESKILL;
|
||||
double dropammofactor = G_SkillProperty(SKILLP_DropAmmoFactor);
|
||||
// Default drop amount is half of regular amount * regular ammo multiplication
|
||||
if (dropammofactor == -1)
|
||||
{
|
||||
dropammofactor = 0.5;
|
||||
flagmask = 0;
|
||||
flagmask = ItemFlag(0);
|
||||
}
|
||||
|
||||
if (dropamount > 0)
|
||||
|
|
|
@ -562,6 +562,21 @@ bool EV_FloorCrushStop (int tag)
|
|||
return true;
|
||||
}
|
||||
|
||||
// same as above but stops any floor mover that was active on the given sector.
|
||||
bool EV_StopFloor(int tag)
|
||||
{
|
||||
FSectorTagIterator it(tag);
|
||||
while (int sec = it.Next())
|
||||
{
|
||||
if (level.sectors[sec].floordata)
|
||||
{
|
||||
SN_StopSequence(&level.sectors[sec], CHAN_FLOOR);
|
||||
level.sectors[sec].floordata->Destroy();
|
||||
level.sectors[sec].floordata = nullptr;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//==========================================================================
|
||||
//
|
||||
// BUILD A STAIRCASE!
|
||||
|
|
|
@ -63,7 +63,6 @@
|
|||
#include "g_levellocals.h"
|
||||
#include "events.h"
|
||||
|
||||
static FRandom pr_obituary ("Obituary");
|
||||
static FRandom pr_botrespawn ("BotRespawn");
|
||||
static FRandom pr_killmobj ("ActorDie");
|
||||
FRandom pr_damagemobj ("ActorTakeDamage");
|
||||
|
@ -187,14 +186,11 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
|||
const char *message;
|
||||
const char *messagename;
|
||||
char gendermessage[1024];
|
||||
int gender;
|
||||
|
||||
// No obituaries for non-players, voodoo dolls or when not wanted
|
||||
if (self->player == NULL || self->player->mo != self || !show_obituaries)
|
||||
return;
|
||||
|
||||
gender = self->player->userinfo.GetGender();
|
||||
|
||||
// Treat voodoo dolls as unknown deaths
|
||||
if (inflictor && inflictor->player && inflictor->player->mo != inflictor)
|
||||
MeansOfDeath = NAME_None;
|
||||
|
@ -218,93 +214,48 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
|||
}
|
||||
|
||||
FString obit = DamageTypeDefinition::GetObituary(mod);
|
||||
if (obit.IsNotEmpty()) messagename = obit;
|
||||
if (attacker == nullptr) messagename = obit;
|
||||
else
|
||||
{
|
||||
switch (mod)
|
||||
{
|
||||
case NAME_Suicide: messagename = "OB_SUICIDE"; break;
|
||||
case NAME_Falling: messagename = "OB_FALLING"; break;
|
||||
case NAME_Crush: messagename = "OB_CRUSH"; break;
|
||||
case NAME_Exit: messagename = "OB_EXIT"; break;
|
||||
case NAME_Drowning: messagename = "OB_WATER"; break;
|
||||
case NAME_Slime: messagename = "OB_SLIME"; break;
|
||||
case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break;
|
||||
case NAME_Suicide: message = "$OB_SUICIDE"; break;
|
||||
case NAME_Falling: message = "$OB_FALLING"; break;
|
||||
case NAME_Crush: message = "$OB_CRUSH"; break;
|
||||
case NAME_Exit: message = "$OB_EXIT"; break;
|
||||
case NAME_Drowning: message = "$OB_WATER"; break;
|
||||
case NAME_Slime: message = "$OB_SLIME"; break;
|
||||
case NAME_Fire: messagename = "$OB_LAVA"; break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for being killed by a voodoo doll.
|
||||
if (inflictor && inflictor->player && inflictor->player->mo != inflictor)
|
||||
{
|
||||
messagename = "OB_VOODOO";
|
||||
messagename = "$OB_VOODOO";
|
||||
}
|
||||
|
||||
if (messagename != NULL)
|
||||
message = GStrings(messagename);
|
||||
|
||||
if (attacker != NULL && message == NULL)
|
||||
{
|
||||
if (attacker == self)
|
||||
{
|
||||
message = GStrings("OB_KILLEDSELF");
|
||||
}
|
||||
else if (attacker->player == NULL)
|
||||
{
|
||||
if (mod == NAME_Telefrag)
|
||||
{
|
||||
message = GStrings("OB_MONTELEFRAG");
|
||||
}
|
||||
else if (mod == NAME_Melee && attacker->GetClass()->HitObituary.IsNotEmpty())
|
||||
{
|
||||
message = attacker->GetClass()->HitObituary;
|
||||
}
|
||||
else if (attacker->GetClass()->Obituary.IsNotEmpty())
|
||||
{
|
||||
message = attacker->GetClass()->Obituary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message == NULL && attacker != NULL && attacker->player != NULL)
|
||||
{
|
||||
if (self->player != attacker->player && self->IsTeammate(attacker))
|
||||
{
|
||||
self = attacker;
|
||||
gender = self->player->userinfo.GetGender();
|
||||
mysnprintf (gendermessage, countof(gendermessage), "OB_FRIENDLY%c", '1' + (pr_obituary() & 3));
|
||||
message = GStrings(gendermessage);
|
||||
message = "$OB_KILLEDSELF";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mod == NAME_Telefrag) message = GStrings("OB_MPTELEFRAG");
|
||||
if (message == NULL)
|
||||
IFVIRTUALPTR(attacker, AActor, GetObituary)
|
||||
{
|
||||
if (inflictor != NULL && inflictor->GetClass()->Obituary.IsNotEmpty())
|
||||
{
|
||||
message = inflictor->GetClass()->Obituary;
|
||||
}
|
||||
if (message == NULL && (dmgflags & DMG_PLAYERATTACK) && attacker->player->ReadyWeapon != NULL)
|
||||
{
|
||||
message = attacker->player->ReadyWeapon->GetClass()->Obituary;
|
||||
}
|
||||
if (message == NULL)
|
||||
{
|
||||
switch (mod)
|
||||
{
|
||||
case NAME_BFGSplash: messagename = "OB_MPBFG_SPLASH"; break;
|
||||
case NAME_Railgun: messagename = "OB_RAILGUN"; break;
|
||||
}
|
||||
if (messagename != NULL)
|
||||
message = GStrings(messagename);
|
||||
}
|
||||
if (message == NULL)
|
||||
{
|
||||
message = attacker->GetClass()->Obituary;
|
||||
VMValue params[] = { attacker, self, inflictor, mod.GetIndex(), !!(dmgflags & DMG_PLAYERATTACK) };
|
||||
FString ret;
|
||||
VMReturn rett(&ret);
|
||||
GlobalVMStack.Call(func, params, countof(params), &rett, 1);
|
||||
if (ret.IsNotEmpty()) message = ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else attacker = self; // for the message creation
|
||||
if (message == nullptr) message = messagename; // fallback to defaults if possible.
|
||||
if (attacker == nullptr) attacker = self; // world
|
||||
if (attacker->player == nullptr) attacker = self; // for the message creation
|
||||
|
||||
if (message != NULL && message[0] == '$')
|
||||
{
|
||||
|
@ -320,7 +271,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
|||
if (message == NULL || strlen(message) <= 0)
|
||||
return;
|
||||
|
||||
SexMessage (message, gendermessage, gender,
|
||||
SexMessage (message, gendermessage, self->player->userinfo.GetGender(),
|
||||
self->player->userinfo.GetName(), attacker->player->userinfo.GetName());
|
||||
Printf (PRINT_MEDIUM, "%s\n", gendermessage);
|
||||
}
|
||||
|
@ -412,23 +363,11 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags)
|
|||
}
|
||||
flags6 |= MF6_KILLED;
|
||||
|
||||
// [RH] Allow the death height to be overridden using metadata.
|
||||
double metaheight = -1;
|
||||
if (DamageType == NAME_Fire)
|
||||
IFVIRTUAL(AActor, GetDeathHeight)
|
||||
{
|
||||
metaheight = GetClass()->BurnHeight;
|
||||
}
|
||||
if (metaheight < 0)
|
||||
{
|
||||
metaheight = GetClass()->DeathHeight;
|
||||
}
|
||||
if (metaheight < 0)
|
||||
{
|
||||
Height *= 0.25;
|
||||
}
|
||||
else
|
||||
{
|
||||
Height = MAX<double> (metaheight, 0);
|
||||
VMValue params[] = { (DObject*)this };
|
||||
VMReturn ret(&Height);
|
||||
GlobalVMStack.Call(func, params, 1, &ret, 1);
|
||||
}
|
||||
|
||||
// [RH] If the thing has a special, execute and remove it
|
||||
|
@ -1021,6 +960,11 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
if (target == source && damage < TELEFRAG_DAMAGE)
|
||||
{
|
||||
damage = int(damage * target->SelfDamageFactor);
|
||||
}
|
||||
|
||||
// [MC] Changed it to check rawdamage here for consistency, even though that doesn't actually do anything
|
||||
// different here. At any rate, invulnerable is being checked before type factoring, which is then being
|
||||
// checked by player cheats/invul/buddha followed by monster buddha. This is inconsistent. Don't let the
|
||||
|
@ -1532,7 +1476,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
|||
woundstate = target->FindState(NAME_Wound, mod);
|
||||
if (woundstate != NULL)
|
||||
{
|
||||
int woundhealth = target->GetClass()->WoundHealth;
|
||||
int woundhealth = target->WoundHealth;
|
||||
|
||||
if (target->health <= woundhealth)
|
||||
{
|
||||
|
|
|
@ -563,6 +563,13 @@ FUNC(LS_Generic_Floor)
|
|||
|
||||
}
|
||||
|
||||
FUNC(LS_Floor_Stop)
|
||||
// Floor_Stop (tag)
|
||||
{
|
||||
return EV_StopFloor(arg0);
|
||||
}
|
||||
|
||||
|
||||
FUNC(LS_Stairs_BuildDown)
|
||||
// Stair_BuildDown (tag, speed, height, delay, reset)
|
||||
{
|
||||
|
@ -860,6 +867,13 @@ FUNC(LS_Ceiling_LowerByTexture)
|
|||
return EV_DoCeiling (DCeiling::ceilLowerByTexture, ln, arg0, SPEED(arg1), 0, 0, CRUSH(arg3), 0, CHANGE(arg4));
|
||||
}
|
||||
|
||||
FUNC(LS_Ceiling_Stop)
|
||||
// Ceiling_Stop (tag)
|
||||
{
|
||||
return EV_StopCeiling(arg0);
|
||||
}
|
||||
|
||||
|
||||
FUNC(LS_Generic_Ceiling)
|
||||
// Generic_Ceiling (tag, speed, height, target, change/model/direct/crush)
|
||||
{
|
||||
|
@ -3614,6 +3628,8 @@ static lnSpecFunc LineSpecials[] =
|
|||
/* 272 */ LS_Stairs_BuildDownDoomSync,
|
||||
/* 273 */ LS_Stairs_BuildUpDoomCrush,
|
||||
/* 274 */ LS_Door_AnimatedClose,
|
||||
/* 275 */ LS_Floor_Stop,
|
||||
/* 276 */ LS_Ceiling_Stop,
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -2282,9 +2282,9 @@ bool P_TryMove(AActor *thing, const DVector2 &pos,
|
|||
}
|
||||
#endif
|
||||
}
|
||||
if (!(thing->flags & MF_TELEPORT) && !(thing->flags3 & MF3_FLOORHUGGER))
|
||||
if (!(thing->flags & MF_TELEPORT) && (!(thing->flags3 & MF3_FLOORHUGGER) || thing->flags5 & MF5_NODROPOFF))
|
||||
{
|
||||
if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > thing->Z())
|
||||
if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > thing->Z() && !(thing->flags3 & MF3_FLOORHUGGER))
|
||||
{ // [RH] Don't let normal missiles climb steps
|
||||
goto pushline;
|
||||
}
|
||||
|
@ -2773,13 +2773,13 @@ bool P_CheckMove(AActor *thing, const DVector2 &pos, int flags)
|
|||
if (thing->Top() > tm.ceilingz)
|
||||
return false;
|
||||
}
|
||||
if (!(thing->flags & MF_TELEPORT) && !(thing->flags3 & MF3_FLOORHUGGER))
|
||||
if (!(thing->flags & MF_TELEPORT) && (!(thing->flags3 & MF3_FLOORHUGGER) || thing->flags5 & MF5_NODROPOFF))
|
||||
{
|
||||
if (tm.floorz - newz > thing->MaxStepHeight)
|
||||
{ // too big a step up
|
||||
return false;
|
||||
}
|
||||
else if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > newz)
|
||||
else if ((thing->flags & MF_MISSILE) && !(thing->flags6 & MF6_STEPMISSILE) && tm.floorz > newz && !(thing->flags3 & MF3_FLOORHUGGER))
|
||||
{ // [RH] Don't let normal missiles climb steps
|
||||
return false;
|
||||
}
|
||||
|
@ -4804,7 +4804,7 @@ void P_TraceBleed(int damage, const DVector3 &pos, AActor *actor, DAngle angle,
|
|||
{
|
||||
if (bleedtrace.HitType == TRACE_HitWall)
|
||||
{
|
||||
PalEntry bloodcolor = actor->GetBloodColor();
|
||||
PalEntry bloodcolor = actor->BloodColor;
|
||||
if (bloodcolor != 0)
|
||||
{
|
||||
bloodcolor.r >>= 1; // the full color is too bright for blood decals
|
||||
|
@ -5681,7 +5681,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom
|
|||
{
|
||||
points = points * splashfactor;
|
||||
}
|
||||
points *= thing->GetClass()->RDFactor;
|
||||
points *= thing->RadiusDamageFactor;
|
||||
|
||||
double check = int(points) * bombdamage;
|
||||
// points and bombdamage should be the same sign (the double cast of 'points' is needed to prevent overflows and incorrect values slipping through.)
|
||||
|
@ -5760,7 +5760,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom
|
|||
dist = clamp<double>(dist - fulldamagedistance, 0, dist);
|
||||
int damage = Scale(bombdamage, bombdistance - int(dist), bombdistance);
|
||||
|
||||
double factor = splashfactor * thing->GetClass()->RDFactor;
|
||||
double factor = splashfactor * thing->RadiusDamageFactor;
|
||||
damage = int(damage * factor);
|
||||
if (damage > 0 || (bombspot->flags7 & MF7_FORCEZERORADIUSDMG))
|
||||
{
|
||||
|
@ -5995,7 +5995,6 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos)
|
|||
{
|
||||
if (!(thing->flags&MF_NOBLOOD))
|
||||
{
|
||||
PalEntry bloodcolor = thing->GetBloodColor();
|
||||
PClassActor *bloodcls = thing->GetBloodType();
|
||||
|
||||
P_TraceBleed (newdam > 0 ? newdam : cpos->crushchange, thing);
|
||||
|
@ -6007,9 +6006,9 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos)
|
|||
|
||||
mo->Vel.X = pr_crunch.Random2() / 16.;
|
||||
mo->Vel.Y = pr_crunch.Random2() / 16.;
|
||||
if (bloodcolor != 0 && !(mo->flags2 & MF2_DONTTRANSLATE))
|
||||
if (thing->BloodTranslation != 0 && !(mo->flags2 & MF2_DONTTRANSLATE))
|
||||
{
|
||||
mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
|
||||
mo->Translation = thing->BloodTranslation;
|
||||
}
|
||||
|
||||
if (!(cl_bloodtype <= 1)) mo->renderflags |= RF_INVISIBLE;
|
||||
|
@ -6018,7 +6017,7 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos)
|
|||
DAngle an = (M_Random() - 128) * (360./256);
|
||||
if (cl_bloodtype >= 1)
|
||||
{
|
||||
P_DrawSplash2(32, thing->PosPlusZ(thing->Height/2), an, 2, bloodcolor);
|
||||
P_DrawSplash2(32, thing->PosPlusZ(thing->Height/2), an, 2, thing->BloodColor);
|
||||
}
|
||||
}
|
||||
if (thing->CrushPainSound != 0 && !S_GetSoundPlayingInfo(thing, thing->CrushPainSound))
|
||||
|
|
180
src/p_mobj.cpp
180
src/p_mobj.cpp
|
@ -312,28 +312,13 @@ DEFINE_FIELD(AActor, ConversationRoot)
|
|||
DEFINE_FIELD(AActor, Conversation)
|
||||
DEFINE_FIELD(AActor, DecalGenerator)
|
||||
DEFINE_FIELD(AActor, fountaincolor)
|
||||
|
||||
DEFINE_FIELD(PClassActor, Obituary)
|
||||
DEFINE_FIELD(PClassActor, HitObituary)
|
||||
DEFINE_FIELD(PClassActor, DeathHeight)
|
||||
DEFINE_FIELD(PClassActor, BurnHeight)
|
||||
DEFINE_FIELD(PClassActor, BloodColor)
|
||||
DEFINE_FIELD(PClassActor, GibHealth)
|
||||
DEFINE_FIELD(PClassActor, WoundHealth)
|
||||
DEFINE_FIELD(PClassActor, FastSpeed)
|
||||
DEFINE_FIELD(PClassActor, RDFactor)
|
||||
DEFINE_FIELD(PClassActor, CameraHeight)
|
||||
DEFINE_FIELD(PClassActor, HowlSound)
|
||||
DEFINE_FIELD(PClassActor, BloodType)
|
||||
DEFINE_FIELD(PClassActor, BloodType2)
|
||||
DEFINE_FIELD(PClassActor, BloodType3)
|
||||
DEFINE_FIELD(PClassActor, DontHurtShooter)
|
||||
DEFINE_FIELD(PClassActor, ExplosionRadius)
|
||||
DEFINE_FIELD(PClassActor, ExplosionDamage)
|
||||
DEFINE_FIELD(PClassActor, MeleeDamage)
|
||||
DEFINE_FIELD(PClassActor, MeleeSound)
|
||||
DEFINE_FIELD(PClassActor, MissileName)
|
||||
DEFINE_FIELD(PClassActor, MissileHeight)
|
||||
DEFINE_FIELD(AActor, CameraHeight)
|
||||
DEFINE_FIELD(AActor, RadiusDamageFactor)
|
||||
DEFINE_FIELD(AActor, SelfDamageFactor)
|
||||
DEFINE_FIELD(AActor, StealthAlpha)
|
||||
DEFINE_FIELD(AActor, WoundHealth)
|
||||
DEFINE_FIELD(AActor, BloodColor)
|
||||
DEFINE_FIELD(AActor, BloodTranslation)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -425,6 +410,8 @@ void AActor::Serialize(FSerializer &arc)
|
|||
A("inventoryid", InventoryID)
|
||||
A("floatbobphase", FloatBobPhase)
|
||||
A("translation", Translation)
|
||||
A("bloodcolor", BloodColor)
|
||||
A("bloodtranslation", BloodTranslation)
|
||||
A("seesound", SeeSound)
|
||||
A("attacksound", AttackSound)
|
||||
A("paimsound", PainSound)
|
||||
|
@ -494,11 +481,17 @@ void AActor::Serialize(FSerializer &arc)
|
|||
A("spriteangle", SpriteAngle)
|
||||
A("spriterotation", SpriteRotation)
|
||||
("alternative", alternative)
|
||||
A("cameraheight", CameraHeight)
|
||||
A("tag", Tag)
|
||||
A("visiblestartangle",VisibleStartAngle)
|
||||
A("visibleendangle",VisibleEndAngle)
|
||||
A("visiblestartpitch",VisibleStartPitch)
|
||||
A("visibleendpitch",VisibleEndPitch);
|
||||
A("visibleendpitch",VisibleEndPitch)
|
||||
A("woundhealth", WoundHealth)
|
||||
A("rdfactor", RadiusDamageFactor)
|
||||
A("selfdamagefactor", SelfDamageFactor)
|
||||
A("stealthalpha", StealthAlpha);
|
||||
|
||||
}
|
||||
|
||||
#undef A
|
||||
|
@ -1340,7 +1333,7 @@ bool P_GiveBody(AActor *actor, int num, int max)
|
|||
// calls while supporting health pickups.
|
||||
if (max <= 0)
|
||||
{
|
||||
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->mo->stamina;
|
||||
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth(true);
|
||||
// [MH] First step in predictable generic morph effects
|
||||
if (player->morphTics)
|
||||
{
|
||||
|
@ -1348,7 +1341,7 @@ bool P_GiveBody(AActor *actor, int num, int max)
|
|||
{
|
||||
if (!(player->MorphStyle & MORPH_ADDSTAMINA))
|
||||
{
|
||||
max -= player->mo->stamina;
|
||||
max -= player->mo->stamina + player->mo->BonusHealth;
|
||||
}
|
||||
}
|
||||
else // old health behaviour
|
||||
|
@ -1356,7 +1349,7 @@ bool P_GiveBody(AActor *actor, int num, int max)
|
|||
max = MAXMORPHHEALTH;
|
||||
if (player->MorphStyle & MORPH_ADDSTAMINA)
|
||||
{
|
||||
max += player->mo->stamina;
|
||||
max += player->mo->stamina + player->mo->BonusHealth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1675,8 +1668,7 @@ bool AActor::Grind(bool items)
|
|||
if (isgeneric) // Not a custom crush state, so colorize it appropriately.
|
||||
{
|
||||
S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE);
|
||||
PalEntry bloodcolor = GetBloodColor();
|
||||
if (bloodcolor!=0) Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
|
||||
Translation = BloodTranslation;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1717,10 +1709,7 @@ bool AActor::Grind(bool items)
|
|||
gib->Alpha = Alpha;
|
||||
gib->Height = 0;
|
||||
gib->radius = 0;
|
||||
|
||||
PalEntry bloodcolor = GetBloodColor();
|
||||
if (bloodcolor != 0)
|
||||
gib->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
|
||||
gib->Translation = BloodTranslation;
|
||||
}
|
||||
S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE);
|
||||
}
|
||||
|
@ -2959,7 +2948,7 @@ void P_ZMovement (AActor *mo, double oldfloorz)
|
|||
mo->Vel.Z = 0;
|
||||
return;
|
||||
}
|
||||
else if (mo->flags3 & MF3_FLOORHUGGER)
|
||||
else if ((mo->flags3 & MF3_FLOORHUGGER) && !(mo->flags5 & MF5_NODROPOFF))
|
||||
{ // Floor huggers can go up steps
|
||||
return;
|
||||
}
|
||||
|
@ -3520,7 +3509,7 @@ int AActor::GetMissileDamage (int mask, int add)
|
|||
|
||||
void AActor::Howl ()
|
||||
{
|
||||
FSoundID howl = GetClass()->HowlSound;
|
||||
FSoundID howl = IntVar(NAME_HowlSound);
|
||||
if (!S_IsActorPlayingSomething(this, CHAN_BODY, howl))
|
||||
{
|
||||
S_Sound (this, CHAN_BODY, howl, 1, ATTN_NORM);
|
||||
|
@ -3822,6 +3811,19 @@ void AActor::SetRoll(DAngle r, bool interpolate)
|
|||
}
|
||||
}
|
||||
|
||||
PClassActor *AActor::GetBloodType(int type) const
|
||||
{
|
||||
IFVIRTUAL(AActor, GetBloodType)
|
||||
{
|
||||
VMValue params[] = { (DObject*)this, type };
|
||||
PClassActor *res;
|
||||
VMReturn ret((void**)&res);
|
||||
GlobalVMStack.Call(func, params, countof(params), &ret, 1);
|
||||
return res;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
DVector3 AActor::GetPortalTransition(double byoffset, sector_t **pSec)
|
||||
{
|
||||
|
@ -4100,9 +4102,9 @@ void AActor::Tick ()
|
|||
else if (visdir < 0)
|
||||
{
|
||||
Alpha -= 1.5/TICRATE;
|
||||
if (Alpha < 0)
|
||||
if (Alpha < StealthAlpha)
|
||||
{
|
||||
Alpha = 0;
|
||||
Alpha = StealthAlpha;
|
||||
visdir = 0;
|
||||
}
|
||||
}
|
||||
|
@ -4823,8 +4825,11 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a
|
|||
actor->renderflags = (actor->renderflags & ~RF_FULLBRIGHT) | ActorRenderFlags::FromInt (st->GetFullbright());
|
||||
actor->touching_sectorlist = nullptr; // NULL head of sector list // phares 3/13/98
|
||||
actor->touching_rendersectors = nullptr;
|
||||
if (G_SkillProperty(SKILLP_FastMonsters) && actor->GetClass()->FastSpeed >= 0)
|
||||
actor->Speed = actor->GetClass()->FastSpeed;
|
||||
if (G_SkillProperty(SKILLP_FastMonsters))
|
||||
{
|
||||
double f = actor->FloatVar(NAME_FastSpeed);
|
||||
if (f >= 0) actor->Speed = f;
|
||||
}
|
||||
|
||||
// set subsector and/or block links
|
||||
actor->LinkToWorld (nullptr, SpawningMapThing);
|
||||
|
@ -5304,6 +5309,7 @@ DEFINE_ACTION_FUNCTION(AActor, AdjustFloorClip)
|
|||
//
|
||||
EXTERN_CVAR (Bool, chasedemo)
|
||||
EXTERN_CVAR(Bool, sv_singleplayerrespawn)
|
||||
EXTERN_CVAR(Float, fov)
|
||||
|
||||
extern bool demonew;
|
||||
|
||||
|
@ -5441,7 +5447,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
|
|||
mobj->sprite = Skins[p->userinfo.GetSkin()].sprite;
|
||||
}
|
||||
|
||||
p->DesiredFOV = p->FOV = 90.f;
|
||||
p->DesiredFOV = p->FOV = fov;
|
||||
p->camera = p->mo;
|
||||
p->playerstate = PST_LIVE;
|
||||
p->refire = 0;
|
||||
|
@ -5814,15 +5820,13 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
|
|||
// [RH] Other things that shouldn't be spawned depending on dmflags
|
||||
if (deathmatch || alwaysapplydmflags)
|
||||
{
|
||||
// Fixme: This needs to be done differently, it's quite broken.
|
||||
if (i->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||
{
|
||||
auto it = static_cast<AInventory*>(GetDefaultByType(i));
|
||||
|
||||
if (dmflags & DF_NO_HEALTH)
|
||||
{
|
||||
if (i->IsDescendantOf (PClass::FindActor(NAME_Health)))
|
||||
return NULL;
|
||||
if (i->TypeName == NAME_Berserk)
|
||||
return NULL;
|
||||
if (i->TypeName == NAME_Megasphere)
|
||||
return NULL;
|
||||
if (it->ItemFlags & IF_ISHEALTH) return nullptr;
|
||||
}
|
||||
if (dmflags & DF_NO_ITEMS)
|
||||
{
|
||||
|
@ -5831,10 +5835,8 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
|
|||
}
|
||||
if (dmflags & DF_NO_ARMOR)
|
||||
{
|
||||
if (i->IsDescendantOf (PClass::FindActor(NAME_Armor)))
|
||||
return NULL;
|
||||
if (i->TypeName == NAME_Megasphere)
|
||||
return NULL;
|
||||
if (it->ItemFlags & IF_ISARMOR) return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5929,13 +5931,13 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
|
|||
mobj->LevelSpawned ();
|
||||
}
|
||||
|
||||
if (mthing->health > 0)
|
||||
mobj->health *= mthing->health;
|
||||
if (mthing->Health > 0)
|
||||
mobj->health = int(mobj->health * mthing->Health);
|
||||
else
|
||||
mobj->health = -mthing->health;
|
||||
if (mthing->health == 0)
|
||||
mobj->health = -int(mthing->Health);
|
||||
if (mthing->Health == 0)
|
||||
mobj->CallDie(NULL, NULL);
|
||||
else if (mthing->health != 1)
|
||||
else if (mthing->Health != 1)
|
||||
mobj->StartHealth = mobj->health;
|
||||
|
||||
return mobj;
|
||||
|
@ -6008,7 +6010,7 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1
|
|||
if (cl_pufftype && updown != 3 && (puff->flags4 & MF4_ALLOWPARTICLES))
|
||||
{
|
||||
P_DrawSplash2 (32, pos, particledir, updown, 1);
|
||||
puff->renderflags |= RF_INVISIBLE;
|
||||
if (cl_pufftype == 1) puff->renderflags |= RF_INVISIBLE;
|
||||
}
|
||||
|
||||
if ((flags & PF_HITTHING) && puff->SeeSound)
|
||||
|
@ -6048,7 +6050,6 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnPuff)
|
|||
void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *originator)
|
||||
{
|
||||
AActor *th;
|
||||
PalEntry bloodcolor = originator->GetBloodColor();
|
||||
PClassActor *bloodcls = originator->GetBloodType();
|
||||
DVector3 pos = pos1;
|
||||
pos.Z += pr_spawnblood.Random2() / 64.;
|
||||
|
@ -6073,9 +6074,9 @@ void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *origina
|
|||
th->tics = 1;
|
||||
}
|
||||
// colorize the blood
|
||||
if (bloodcolor != 0 && !(th->flags2 & MF2_DONTTRANSLATE))
|
||||
if (!(th->flags2 & MF2_DONTTRANSLATE))
|
||||
{
|
||||
th->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
|
||||
th->Translation = originator->BloodTranslation;
|
||||
}
|
||||
|
||||
// Moved out of the blood actor so that replacing blood is easier
|
||||
|
@ -6132,7 +6133,7 @@ void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *origina
|
|||
}
|
||||
|
||||
if (bloodtype >= 1)
|
||||
P_DrawSplash2 (40, pos, dir, 2, bloodcolor);
|
||||
P_DrawSplash2 (40, pos, dir, 2, originator->BloodColor);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, SpawnBlood)
|
||||
|
@ -6156,7 +6157,6 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnBlood)
|
|||
|
||||
void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle)
|
||||
{
|
||||
PalEntry bloodcolor = originator->GetBloodColor();
|
||||
PClassActor *bloodcls = originator->GetBloodType(1);
|
||||
|
||||
int bloodtype = cl_bloodtype;
|
||||
|
@ -6175,16 +6175,16 @@ void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle)
|
|||
mo->Vel.Z = 3;
|
||||
|
||||
// colorize the blood!
|
||||
if (bloodcolor!=0 && !(mo->flags2 & MF2_DONTTRANSLATE))
|
||||
if (!(mo->flags2 & MF2_DONTTRANSLATE))
|
||||
{
|
||||
mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
|
||||
mo->Translation = originator->BloodTranslation;
|
||||
}
|
||||
|
||||
if (!(bloodtype <= 1)) mo->renderflags |= RF_INVISIBLE;
|
||||
}
|
||||
if (bloodtype >= 1)
|
||||
{
|
||||
P_DrawSplash2 (40, pos, hitangle-180., 2, bloodcolor);
|
||||
P_DrawSplash2 (40, pos, hitangle-180., 2, originator->BloodColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6196,7 +6196,6 @@ void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle)
|
|||
|
||||
void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle)
|
||||
{
|
||||
PalEntry bloodcolor = originator->GetBloodColor();
|
||||
PClassActor *bloodcls = originator->GetBloodType(2);
|
||||
|
||||
int bloodtype = cl_bloodtype;
|
||||
|
@ -6217,16 +6216,16 @@ void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle)
|
|||
mo->target = originator;
|
||||
|
||||
// colorize the blood!
|
||||
if (bloodcolor != 0 && !(mo->flags2 & MF2_DONTTRANSLATE))
|
||||
if (!(mo->flags2 & MF2_DONTTRANSLATE))
|
||||
{
|
||||
mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
|
||||
mo->Translation = originator->BloodTranslation;
|
||||
}
|
||||
|
||||
if (!(bloodtype <= 1)) mo->renderflags |= RF_INVISIBLE;
|
||||
}
|
||||
if (bloodtype >= 1)
|
||||
{
|
||||
P_DrawSplash2(40, pos + add, hitangle - 180., 2, bloodcolor);
|
||||
P_DrawSplash2(40, pos + add, hitangle - 180., 2, originator->BloodColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6252,7 +6251,6 @@ DEFINE_ACTION_FUNCTION(AActor, BloodSplatter)
|
|||
|
||||
void P_RipperBlood (AActor *mo, AActor *bleeder)
|
||||
{
|
||||
PalEntry bloodcolor = bleeder->GetBloodColor();
|
||||
PClassActor *bloodcls = bleeder->GetBloodType();
|
||||
|
||||
double xo = pr_ripperblood.Random2() / 16.;
|
||||
|
@ -6278,16 +6276,16 @@ void P_RipperBlood (AActor *mo, AActor *bleeder)
|
|||
th->tics += pr_ripperblood () & 3;
|
||||
|
||||
// colorize the blood!
|
||||
if (bloodcolor!=0 && !(th->flags2 & MF2_DONTTRANSLATE))
|
||||
if (!(th->flags2 & MF2_DONTTRANSLATE))
|
||||
{
|
||||
th->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a);
|
||||
th->Translation = bleeder->BloodTranslation;
|
||||
}
|
||||
|
||||
if (!(bloodtype <= 1)) th->renderflags |= RF_INVISIBLE;
|
||||
}
|
||||
if (bloodtype >= 1)
|
||||
{
|
||||
P_DrawSplash2(28, pos, bleeder->AngleTo(mo) + 180., 0, bloodcolor);
|
||||
P_DrawSplash2(28, pos, bleeder->AngleTo(mo) + 180., 0, bleeder->BloodColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6696,10 +6694,14 @@ static double GetDefaultSpeed(PClassActor *type)
|
|||
{
|
||||
if (type == NULL)
|
||||
return 0;
|
||||
else if (G_SkillProperty(SKILLP_FastMonsters) && type->FastSpeed >= 0)
|
||||
return type->FastSpeed;
|
||||
else
|
||||
return GetDefaultByType(type)->Speed;
|
||||
|
||||
auto def = GetDefaultByType(type);
|
||||
if (G_SkillProperty(SKILLP_FastMonsters))
|
||||
{
|
||||
double f = def->FloatVar(NAME_FastSpeed);
|
||||
if (f >= 0) return f;
|
||||
}
|
||||
return def->Speed;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, GetDefaultSpeed)
|
||||
|
@ -7465,9 +7467,10 @@ void AActor::Crash()
|
|||
{
|
||||
FState *crashstate = NULL;
|
||||
|
||||
int gibh = GetGibHealth();
|
||||
if (DamageType != NAME_None)
|
||||
{
|
||||
if (health < GetGibHealth())
|
||||
if (health < gibh)
|
||||
{ // Extreme death
|
||||
FName labels[] = { NAME_Crash, NAME_Extreme, DamageType };
|
||||
crashstate = FindState (3, labels, true);
|
||||
|
@ -7479,7 +7482,7 @@ void AActor::Crash()
|
|||
}
|
||||
if (crashstate == NULL)
|
||||
{
|
||||
if (health < GetGibHealth())
|
||||
if (health < gibh)
|
||||
{ // Extreme death
|
||||
crashstate = FindState(NAME_Crash, NAME_Extreme);
|
||||
}
|
||||
|
@ -7585,21 +7588,20 @@ void AActor::Revive()
|
|||
|
||||
int AActor::GetGibHealth() const
|
||||
{
|
||||
int gibhealth = GetClass()->GibHealth;
|
||||
|
||||
if (gibhealth != INT_MIN)
|
||||
IFVIRTUAL(AActor, GetGibHealth)
|
||||
{
|
||||
return -abs(gibhealth);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -int(SpawnHealth() * gameinfo.gibfactor);
|
||||
VMValue params[] = { (DObject*)this };
|
||||
int h;
|
||||
VMReturn ret(&h);
|
||||
GlobalVMStack.Call(func, params, 1, &ret, 1);
|
||||
return h;
|
||||
}
|
||||
return -SpawnHealth();
|
||||
}
|
||||
|
||||
double AActor::GetCameraHeight() const
|
||||
{
|
||||
return GetClass()->CameraHeight == INT_MIN ? Height / 2 : GetClass()->CameraHeight;
|
||||
return CameraHeight == INT_MIN ? Height / 2 : CameraHeight;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight)
|
||||
|
@ -8278,9 +8280,9 @@ void PrintMiscActorInfo(AActor *query)
|
|||
query->args[0], query->args[1], query->args[2], query->args[3],
|
||||
query->args[4], query->special1, query->special2);
|
||||
Printf("\nTID: %d", query->tid);
|
||||
Printf("\nCoord= x: %f, y: %f, z:%f, floor:%f, ceiling:%f.",
|
||||
Printf("\nCoord= x: %f, y: %f, z:%f, floor:%f, ceiling:%f, height= %f",
|
||||
query->X(), query->Y(), query->Z(),
|
||||
query->floorz, query->ceilingz);
|
||||
query->floorz, query->ceilingz, query->Height);
|
||||
Printf("\nSpeed= %f, velocity= x:%f, y:%f, z:%f, combined:%f.\n",
|
||||
query->Speed, query->Vel.X, query->Vel.Y, query->Vel.Z, query->Vel.Length());
|
||||
Printf("Scale: x:%f, y:%f\n", query->Scale.X, query->Scale.Y);
|
||||
|
|
|
@ -536,6 +536,7 @@ void P_FireWeapon (player_t *player, FState *state)
|
|||
return;
|
||||
}
|
||||
|
||||
player->WeaponState &= ~WF_WEAPONBOBBING;
|
||||
player->mo->PlayAttacking ();
|
||||
weapon->bAltFire = false;
|
||||
if (state == nullptr)
|
||||
|
@ -572,6 +573,7 @@ void P_FireWeaponAlt (player_t *player, FState *state)
|
|||
return;
|
||||
}
|
||||
|
||||
player->WeaponState &= ~WF_WEAPONBOBBING;
|
||||
player->mo->PlayAttacking ();
|
||||
weapon->bAltFire = true;
|
||||
|
||||
|
|
|
@ -1742,7 +1742,7 @@ void P_LoadThings (MapData * map)
|
|||
mti[i].ClassFilter = 0xffff; // Doom map format doesn't have class flags so spawn for all player classes
|
||||
mti[i].RenderStyle = STYLE_Count;
|
||||
mti[i].Alpha = -1;
|
||||
mti[i].health = 1;
|
||||
mti[i].Health = 1;
|
||||
mti[i].FloatbobPhase = -1;
|
||||
|
||||
mti[i].pos.X = LittleShort(mt->x);
|
||||
|
@ -1838,7 +1838,7 @@ void P_LoadThings2 (MapData * map)
|
|||
mti[i].Gravity = 1;
|
||||
mti[i].RenderStyle = STYLE_Count;
|
||||
mti[i].Alpha = -1;
|
||||
mti[i].health = 1;
|
||||
mti[i].Health = 1;
|
||||
mti[i].FloatbobPhase = -1;
|
||||
}
|
||||
delete[] mtp;
|
||||
|
|
|
@ -452,6 +452,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t
|
|||
bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, int tag, double speed, double speed2, double height, int crush, int silent, int change, DCeiling::ECrushMode hexencrush = DCeiling::ECrushMode::crushDoom);
|
||||
|
||||
bool EV_CeilingCrushStop (int tag, bool remove);
|
||||
bool EV_StopCeiling(int tag);
|
||||
void P_ActivateInStasisCeiling (int tag);
|
||||
|
||||
|
||||
|
@ -565,6 +566,7 @@ bool EV_DoFloor(DFloor::EFloor floortype, line_t *line, int tag,
|
|||
double speed, double height, int crush, int change, bool hexencrush, bool hereticlower = false);
|
||||
|
||||
bool EV_FloorCrushStop (int tag);
|
||||
bool EV_StopFloor(int tag);
|
||||
bool EV_DoDonut (int tag, line_t *line, double pillarspeed, double slimespeed);
|
||||
|
||||
class DElevator : public DMover
|
||||
|
|
|
@ -515,11 +515,10 @@ public:
|
|||
FString arg0str, arg1str;
|
||||
|
||||
memset(th, 0, sizeof(*th));
|
||||
double healthfactor = 1;
|
||||
th->Gravity = 1;
|
||||
th->RenderStyle = STYLE_Count;
|
||||
th->Alpha = -1;
|
||||
th->health = 1;
|
||||
th->Health = 1;
|
||||
th->FloatbobPhase = -1;
|
||||
sc.MustGetToken('{');
|
||||
while (!sc.CheckToken('}'))
|
||||
|
@ -739,52 +738,38 @@ public:
|
|||
break;
|
||||
|
||||
case NAME_Alpha:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->Alpha = CheckFloat(key);
|
||||
break;
|
||||
|
||||
case NAME_FillColor:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->fillcolor = CheckInt(key);
|
||||
break;
|
||||
|
||||
case NAME_Health:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->health = CheckInt(key);
|
||||
break;
|
||||
|
||||
case NAME_HealthFactor:
|
||||
CHECK_N(Zd | Zdt)
|
||||
healthfactor = CheckFloat(key);
|
||||
th->Health = CheckFloat(key);
|
||||
break;
|
||||
|
||||
case NAME_Score:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->score = CheckInt(key);
|
||||
break;
|
||||
|
||||
case NAME_Pitch:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->pitch = (short)CheckInt(key);
|
||||
break;
|
||||
|
||||
case NAME_Roll:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->roll = (short)CheckInt(key);
|
||||
break;
|
||||
|
||||
case NAME_ScaleX:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->Scale.X = CheckFloat(key);
|
||||
break;
|
||||
|
||||
case NAME_ScaleY:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->Scale.Y = CheckFloat(key);
|
||||
break;
|
||||
|
||||
case NAME_Scale:
|
||||
CHECK_N(Zd | Zdt)
|
||||
th->Scale.X = th->Scale.Y = CheckFloat(key);
|
||||
break;
|
||||
|
||||
|
@ -808,7 +793,6 @@ public:
|
|||
{
|
||||
th->args[1] = -FName(arg1str);
|
||||
}
|
||||
th->health = int(th->health * healthfactor);
|
||||
// Thing specials are only valid in namespaces with Hexen-type specials
|
||||
// and in ZDoomTranslated - which will use the translator on them.
|
||||
if (namespc == NAME_ZDoomTranslated)
|
||||
|
|
|
@ -89,6 +89,13 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO
|
|||
ColorSetList ColorSets;
|
||||
PainFlashList PainFlashes;
|
||||
|
||||
// [Nash] FOV cvar setting
|
||||
CUSTOM_CVAR(Float, fov, 90.f, CVAR_ARCHIVE | CVAR_USERINFO | CVAR_NOINITCALL)
|
||||
{
|
||||
player_t *p = &players[consoleplayer];
|
||||
p->SetFOV(fov);
|
||||
}
|
||||
|
||||
struct PredictPos
|
||||
{
|
||||
int gametic;
|
||||
|
@ -551,6 +558,40 @@ int player_t::GetSpawnClass()
|
|||
return static_cast<APlayerPawn*>(GetDefaultByType(type))->SpawnMask;
|
||||
}
|
||||
|
||||
// [Nash] Set FOV
|
||||
void player_t::SetFOV(float fov)
|
||||
{
|
||||
player_t *p = &players[consoleplayer];
|
||||
if (p != nullptr && p->mo != nullptr)
|
||||
{
|
||||
if (dmflags & DF_NO_FOV)
|
||||
{
|
||||
if (consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
Net_WriteByte(DEM_MYFOV);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("A setting controller has disabled FOV changes.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte(DEM_MYFOV);
|
||||
}
|
||||
Net_WriteByte((BYTE)clamp<float>(fov, 5.f, 179.f));
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_PlayerInfo, SetFOV)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(player_t);
|
||||
PARAM_FLOAT(fov);
|
||||
self->SetFOV((float)fov);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// EnumColorsets
|
||||
|
@ -741,6 +782,7 @@ void APlayerPawn::Serialize(FSerializer &arc)
|
|||
|
||||
arc("jumpz", JumpZ, def->JumpZ)
|
||||
("maxhealth", MaxHealth, def->MaxHealth)
|
||||
("bonushealth", BonusHealth, def->BonusHealth)
|
||||
("runhealth", RunHealth, def->RunHealth)
|
||||
("spawnmask", SpawnMask, def->SpawnMask)
|
||||
("forwardmove1", ForwardMove1, def->ForwardMove1)
|
||||
|
@ -1310,15 +1352,18 @@ const char *APlayerPawn::GetSoundClass() const
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
int APlayerPawn::GetMaxHealth() const
|
||||
int APlayerPawn::GetMaxHealth(bool withupgrades) const
|
||||
{
|
||||
return MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth);
|
||||
int ret = MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth);
|
||||
if (withupgrades) ret += stamina + BonusHealth;
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(APlayerPawn, GetMaxHealth)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(APlayerPawn);
|
||||
ACTION_RETURN_INT(self->GetMaxHealth());
|
||||
PARAM_BOOL_DEF(withupgrades);
|
||||
ACTION_RETURN_INT(self->GetMaxHealth(withupgrades));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -2829,7 +2874,7 @@ void P_PlayerThink (player_t *player)
|
|||
// Apply degeneration.
|
||||
if (dmflags2 & DF2_YES_DEGENERATION)
|
||||
{
|
||||
int maxhealth = player->mo->GetMaxHealth() + player->mo->stamina;
|
||||
int maxhealth = player->mo->GetMaxHealth(true);
|
||||
if ((level.time % TICRATE) == 0 && player->health > maxhealth)
|
||||
{
|
||||
if (player->health - 5 < maxhealth)
|
||||
|
@ -3302,6 +3347,7 @@ bool P_IsPlayerTotallyFrozen(const player_t *player)
|
|||
|
||||
DEFINE_FIELD(APlayerPawn, crouchsprite)
|
||||
DEFINE_FIELD(APlayerPawn, MaxHealth)
|
||||
DEFINE_FIELD(APlayerPawn, BonusHealth)
|
||||
DEFINE_FIELD(APlayerPawn, MugShotMaxHealth)
|
||||
DEFINE_FIELD(APlayerPawn, RunHealth)
|
||||
DEFINE_FIELD(APlayerPawn, PlayerFlags)
|
||||
|
@ -3326,19 +3372,14 @@ DEFINE_FIELD(APlayerPawn, FlechetteType)
|
|||
DEFINE_FIELD(APlayerPawn, DamageFade)
|
||||
DEFINE_FIELD(APlayerPawn, ViewBob)
|
||||
DEFINE_FIELD(APlayerPawn, FullHeight)
|
||||
|
||||
DEFINE_FIELD(APlayerPawn, HealingRadiusType)
|
||||
DEFINE_FIELD(APlayerPawn, SoundClass)
|
||||
DEFINE_FIELD(APlayerPawn, Face)
|
||||
DEFINE_FIELD(APlayerPawn, Portrait)
|
||||
DEFINE_FIELD(APlayerPawn, Slot)
|
||||
DEFINE_FIELD(APlayerPawn, InvulMode)
|
||||
DEFINE_FIELD(APlayerPawn, HexenArmor)
|
||||
DEFINE_FIELD(APlayerPawn, ColorRangeStart)
|
||||
DEFINE_FIELD(APlayerPawn, ColorRangeEnd)
|
||||
|
||||
DEFINE_FIELD(PClassActor, DisplayName)
|
||||
|
||||
DEFINE_FIELD_X(PlayerInfo, player_t, mo)
|
||||
DEFINE_FIELD_X(PlayerInfo, player_t, playerstate)
|
||||
DEFINE_FIELD_X(PlayerInfo, player_t, original_oldbuttons)
|
||||
|
|
|
@ -395,9 +395,10 @@ void MessagePump (const SDL_Event &sev)
|
|||
{
|
||||
event.type = EV_GUI_Event;
|
||||
event.subtype = sev.type == SDL_KEYDOWN ? EV_GUI_KeyDown : EV_GUI_KeyUp;
|
||||
event.data3 = ((sev.key.keysym.mod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
|
||||
((sev.key.keysym.mod & KMOD_CTRL) ? GKM_CTRL : 0) |
|
||||
((sev.key.keysym.mod & KMOD_ALT) ? GKM_ALT : 0);
|
||||
SDL_Keymod kmod = SDL_GetModState();
|
||||
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
|
||||
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
|
||||
((kmod & KMOD_ALT) ? GKM_ALT : 0);
|
||||
|
||||
if (event.subtype == EV_GUI_KeyDown)
|
||||
{
|
||||
|
@ -458,6 +459,7 @@ void MessagePump (const SDL_Event &sev)
|
|||
event.type = EV_GUI_Event;
|
||||
event.subtype = EV_GUI_Char;
|
||||
event.data1 = sev.text.text[0];
|
||||
event.data2 = !!(SDL_GetModState() & KMOD_ALT);
|
||||
D_PostEvent (&event);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -218,8 +218,11 @@ bool FZipFile::Open(bool quiet)
|
|||
char *dirptr = (char*)directory;
|
||||
FZipLump *lump_p = Lumps;
|
||||
|
||||
// Check if all files have the same prefix so that this can be stripped out.
|
||||
FString name0;
|
||||
bool foundspeciallump = false;
|
||||
|
||||
// Check if all files have the same prefix so that this can be stripped out.
|
||||
// This will only be done if there is either a MAPINFO, ZMAPINFO or GAMEINFO lump in the subdirectory, denoting a ZDoom mod.
|
||||
if (NumLumps > 1) for (DWORD i = 0; i < NumLumps; i++)
|
||||
{
|
||||
FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr;
|
||||
|
@ -251,6 +254,7 @@ bool FZipFile::Open(bool quiet)
|
|||
!name.Compare("voxels/") ||
|
||||
!name.Compare("colormaps/") ||
|
||||
!name.Compare("acs/") ||
|
||||
!name.Compare("maps/") ||
|
||||
!name.Compare("voices/") ||
|
||||
!name.Compare("patches/") ||
|
||||
!name.Compare("graphics/") ||
|
||||
|
@ -266,6 +270,23 @@ bool FZipFile::Open(bool quiet)
|
|||
name0 = "";
|
||||
break;
|
||||
}
|
||||
else if (!foundspeciallump)
|
||||
{
|
||||
// at least one of the more common definition lumps must be present.
|
||||
if (name.IndexOf(name0 + "mapinfo") == 0) foundspeciallump = true;
|
||||
else if (name.IndexOf(name0 + "zmapinfo") == 0) foundspeciallump = true;
|
||||
else if (name.IndexOf(name0 + "gameinfo") == 0) foundspeciallump = true;
|
||||
else if (name.IndexOf(name0 + "sndinfo") == 0) foundspeciallump = true;
|
||||
else if (name.IndexOf(name0 + "sbarinfo") == 0) foundspeciallump = true;
|
||||
else if (name.IndexOf(name0 + "menudef") == 0) foundspeciallump = true;
|
||||
else if (name.IndexOf(name0 + "gldefs") == 0) foundspeciallump = true;
|
||||
else if (name.IndexOf(name0 + "animdefs") == 0) foundspeciallump = true;
|
||||
else if (name.IndexOf(name0 + "decorate.") == 0) foundspeciallump = true; // DECORATE is a common subdirectory name, so the check needs to be a bit different.
|
||||
else if (name.Compare(name0 + "decorate") == 0) foundspeciallump = true;
|
||||
else if (name.IndexOf(name0 + "zscript.") == 0) foundspeciallump = true; // same here.
|
||||
else if (name.Compare(name0 + "zscript") == 0) foundspeciallump = true;
|
||||
else if (name.Compare(name0 + "maps/") == 0) foundspeciallump = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6088,19 +6088,85 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
|||
|
||||
if (Object->ExprType == EFX_Identifier)
|
||||
{
|
||||
auto id = static_cast<FxIdentifier *>(Object)->Identifier;
|
||||
// If the left side is a class name for a static member function call it needs to be resolved manually
|
||||
// because the resulting value type would cause problems in nearly every other place where identifiers are being used.
|
||||
ccls = FindStructType(static_cast<FxIdentifier *>(Object)->Identifier, ctx);
|
||||
if (ccls != nullptr) static_cast<FxIdentifier *>(Object)->noglobal = true;
|
||||
ccls = FindStructType(id, ctx);
|
||||
if (ccls != nullptr)
|
||||
{
|
||||
static_cast<FxIdentifier *>(Object)->noglobal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PType *type;
|
||||
// Another special case to deal with here is constants assigned to non-struct types. The code below cannot deal with them so it needs to be done here explicitly.
|
||||
// Thanks to the messed up search logic of the type system, which doesn't allow any search by type name for the basic types at all,
|
||||
// we have to do this manually, though and check for all types that may have values attached explicitly.
|
||||
// (What's the point of attached fields to types if you cannot even search for the types...???)
|
||||
switch (id)
|
||||
{
|
||||
default:
|
||||
type = nullptr;
|
||||
break;
|
||||
|
||||
case NAME_Byte:
|
||||
case NAME_uint8:
|
||||
type = TypeUInt8;
|
||||
break;
|
||||
|
||||
case NAME_sByte:
|
||||
case NAME_int8:
|
||||
type = TypeSInt8;
|
||||
break;
|
||||
|
||||
case NAME_uShort:
|
||||
case NAME_uint16:
|
||||
type = TypeUInt16;
|
||||
break;
|
||||
|
||||
case NAME_Short:
|
||||
case NAME_int16:
|
||||
type = TypeSInt16;
|
||||
break;
|
||||
|
||||
case NAME_Int:
|
||||
type = TypeSInt32;
|
||||
break;
|
||||
|
||||
case NAME_uInt:
|
||||
type = TypeUInt32;
|
||||
break;
|
||||
|
||||
case NAME_Float:
|
||||
type = TypeFloat32;
|
||||
break;
|
||||
|
||||
case NAME_Double:
|
||||
type = TypeFloat64;
|
||||
break;
|
||||
}
|
||||
if (type != nullptr)
|
||||
{
|
||||
auto sym = type->Symbols.FindSymbol(Identifier, true);
|
||||
if (sym != nullptr)
|
||||
{
|
||||
// non-struct symbols must be constant numbers and can only be defined internally.
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
||||
auto sn = static_cast<PSymbolConstNumeric*>(sym);
|
||||
|
||||
VMValue vmv;
|
||||
if (sn->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) vmv = sn->Value;
|
||||
else vmv = sn->Float;
|
||||
auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition);
|
||||
delete this;
|
||||
return x->Resolve(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_RESOLVE(Object, ctx);
|
||||
|
||||
if (Identifier == FName("allmap"))
|
||||
{
|
||||
int a = 2;
|
||||
}
|
||||
|
||||
// check for class or struct constants if the left side is a type name.
|
||||
if (Object->ValueType == TypeError)
|
||||
{
|
||||
|
@ -6371,7 +6437,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
|
|||
ExpEmit ob = obj->Emit(build);
|
||||
ob.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_META, meta.RegNum, ob.RegNum);
|
||||
build->Emit(OP_CLSS, meta.RegNum, ob.RegNum);
|
||||
build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
return meta;
|
||||
|
||||
|
@ -8832,7 +8898,7 @@ ExpEmit FxGetClass::Emit(VMFunctionBuilder *build)
|
|||
ExpEmit op = Self->Emit(build);
|
||||
op.Free(build);
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
build->Emit(OP_META, to.RegNum, op.RegNum);
|
||||
build->Emit(OP_CLSS, to.RegNum, op.RegNum);
|
||||
return to;
|
||||
}
|
||||
|
||||
|
@ -8873,7 +8939,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build)
|
|||
if (Self->IsObject())
|
||||
{
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
build->Emit(OP_META, to.RegNum, op.RegNum);
|
||||
build->Emit(OP_CLSS, to.RegNum, op.RegNum);
|
||||
op = to;
|
||||
op.Free(build);
|
||||
}
|
||||
|
|
|
@ -846,6 +846,7 @@ void FFunctionBuildList::Build()
|
|||
{
|
||||
int errorcount = 0;
|
||||
int codesize = 0;
|
||||
int datasize = 0;
|
||||
FILE *dump = nullptr;
|
||||
|
||||
if (Args->CheckParm("-dumpdisasm")) dump = fopen("disasm.txt", "w");
|
||||
|
@ -927,6 +928,8 @@ void FFunctionBuildList::Build()
|
|||
{
|
||||
DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len());
|
||||
codesize += sfunc->CodeSize;
|
||||
datasize += sfunc->LineInfoCount * sizeof(FStatementInfo) + sfunc->ExtraSpace + sfunc->NumKonstD * sizeof(int) +
|
||||
sfunc->NumKonstA * sizeof(void*) + sfunc->NumKonstF * sizeof(double) + sfunc->NumKonstS * sizeof(FString);
|
||||
}
|
||||
sfunc->Unsafe = ctx.Unsafe;
|
||||
}
|
||||
|
@ -944,10 +947,11 @@ void FFunctionBuildList::Build()
|
|||
}
|
||||
if (dump != nullptr)
|
||||
{
|
||||
fprintf(dump, "\n*************************************************************************\n%i code bytes\n", codesize * 4);
|
||||
fprintf(dump, "\n*************************************************************************\n%i code bytes\n%i data bytes", codesize * 4, datasize);
|
||||
fclose(dump);
|
||||
}
|
||||
FScriptPosition::StrictErrors = false;
|
||||
mItems.Clear();
|
||||
mItems.ShrinkToFit();
|
||||
FxAlloc.FreeAllBlocks();
|
||||
}
|
|
@ -223,7 +223,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns)
|
|||
{
|
||||
extra.DeathHeight = ((AActor*)(type->Defaults))->Height;
|
||||
}
|
||||
type->DeathHeight = extra.DeathHeight;
|
||||
((AActor*)(type->Defaults))->FloatVar("DeathHeight") = extra.DeathHeight;
|
||||
}
|
||||
bag.statedef.SetStateLabel("Death", &type->OwnedStates[extra.DeathStart]);
|
||||
}
|
||||
|
@ -262,7 +262,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns)
|
|||
}
|
||||
|
||||
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->Height;
|
||||
type->BurnHeight = extra.BurnHeight;
|
||||
((AActor*)(type->Defaults))->FloatVar("BurnHeight") = extra.BurnHeight;
|
||||
|
||||
bag.statedef.SetStateLabel("Burn", &type->OwnedStates[extra.FireDeathStart]);
|
||||
}
|
||||
|
@ -445,18 +445,18 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
|
|||
else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius"))
|
||||
{
|
||||
sc.MustGetNumber ();
|
||||
bag.Info->ExplosionRadius = sc.Number;
|
||||
defaults->IntVar(NAME_ExplosionRadius) = sc.Number;
|
||||
extra.bExplosive = true;
|
||||
}
|
||||
else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage"))
|
||||
{
|
||||
sc.MustGetNumber ();
|
||||
bag.Info->ExplosionDamage = sc.Number;
|
||||
defaults->IntVar(NAME_ExplosionDamage) = sc.Number;
|
||||
extra.bExplosive = true;
|
||||
}
|
||||
else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter"))
|
||||
{
|
||||
bag.Info->DontHurtShooter = true;
|
||||
defaults->BoolVar(NAME_DontHurtShooter) = true;
|
||||
}
|
||||
else if (def == DEF_Projectile && sc.Compare ("Damage"))
|
||||
{
|
||||
|
@ -541,11 +541,11 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
|
|||
else if (def == DEF_Pickup && sc.Compare ("PickupMessage"))
|
||||
{
|
||||
sc.MustGetString ();
|
||||
bag.Info->PickupMsg = sc.String;
|
||||
inv->StringVar(NAME_PickupMsg) = sc.String;
|
||||
}
|
||||
else if (def == DEF_Pickup && sc.Compare ("Respawns"))
|
||||
{
|
||||
inv->BoolVar("Respawnable") = true;
|
||||
inv->BoolVar(NAME_Respawnable) = true;
|
||||
}
|
||||
else if (def == DEF_BreakableDecoration && sc.Compare ("SolidOnDeath"))
|
||||
{
|
||||
|
|
|
@ -827,7 +827,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul
|
|||
if (i > 0) sc.MustGetStringName(",");
|
||||
if (f->Flags & VARF_Meta)
|
||||
{
|
||||
addr = ((char*)bag.Info) + f->Offset;
|
||||
addr = ((char*)bag.Info->Meta) + f->Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -867,7 +867,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul
|
|||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PString)))
|
||||
{
|
||||
sc.MustGetString();
|
||||
*(FString*)addr = sc.String;
|
||||
*(FString*)addr = strbin1(sc.String);
|
||||
}
|
||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
||||
{
|
||||
|
|
|
@ -430,6 +430,8 @@ static FFlagDef InventoryFlagDefs[] =
|
|||
DEFINE_FLAG(IF, TRANSFER, AInventory, ItemFlags),
|
||||
DEFINE_FLAG(IF, NOTELEPORTFREEZE, AInventory, ItemFlags),
|
||||
DEFINE_FLAG(IF, NOSCREENBLINK, AInventory, ItemFlags),
|
||||
DEFINE_FLAG(IF, ISARMOR, AInventory, ItemFlags),
|
||||
DEFINE_FLAG(IF, ISHEALTH, AInventory, ItemFlags),
|
||||
|
||||
DEFINE_DUMMY_FLAG(FORCERESPAWNINSURVIVAL, false),
|
||||
|
||||
|
|
|
@ -592,24 +592,13 @@ DEFINE_PROPERTY(health, I, Actor)
|
|||
defaults->health=id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(gibhealth, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->GibHealth = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(woundhealth, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->WoundHealth = id;
|
||||
defaults->WoundHealth = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -888,16 +877,6 @@ DEFINE_PROPERTY(activesound, S, Actor)
|
|||
defaults->ActiveSound = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(howlsound, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->HowlSound = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -981,75 +960,6 @@ DEFINE_PROPERTY(alpha, F, Actor)
|
|||
defaults->Alpha = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(obituary, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->Obituary = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(hitobituary, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->HitObituary = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(donthurtshooter, 0, Actor)
|
||||
{
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->DontHurtShooter = true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(explosionradius, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->ExplosionRadius = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(explosiondamage, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->ExplosionDamage = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(deathheight, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(h, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->DeathHeight = MAX(0., h);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(burnheight, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(h, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->BurnHeight = MAX(0., h);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1068,16 +978,6 @@ DEFINE_PROPERTY(meleethreshold, F, Actor)
|
|||
defaults->meleethreshold = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(meleedamage, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->MeleeDamage = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1087,36 +987,6 @@ DEFINE_PROPERTY(meleerange, F, Actor)
|
|||
defaults->meleerange = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(meleesound, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->MeleeSound = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(missiletype, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->MissileName = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(missileheight, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->MissileHeight = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1183,13 +1053,11 @@ DEFINE_PROPERTY(bloodcolor, C, Actor)
|
|||
{
|
||||
PROP_COLOR_PARM(color, 0);
|
||||
|
||||
PalEntry pe = color;
|
||||
pe.a = CreateBloodTranslation(pe);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->BloodColor = pe;
|
||||
defaults->BloodColor = color;
|
||||
defaults->BloodColor.a = 255; // a should not be 0.
|
||||
defaults->BloodTranslation = TRANSLATION(TRANSLATION_Blood, CreateBloodTranslation(color));
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1199,26 +1067,23 @@ DEFINE_PROPERTY(bloodtype, Sss, Actor)
|
|||
PROP_STRING_PARM(str1, 1)
|
||||
PROP_STRING_PARM(str2, 2)
|
||||
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
PClassActor *ainfo = static_cast<PClassActor *>(info);
|
||||
|
||||
FName blood = str;
|
||||
// normal blood
|
||||
ainfo->BloodType = blood;
|
||||
defaults->NameVar("BloodType") = blood;
|
||||
|
||||
if (PROP_PARM_COUNT > 1)
|
||||
{
|
||||
blood = str1;
|
||||
}
|
||||
// blood splatter
|
||||
ainfo->BloodType2 = blood;
|
||||
defaults->NameVar("BloodType2") = blood;
|
||||
|
||||
if (PROP_PARM_COUNT > 2)
|
||||
{
|
||||
blood = str2;
|
||||
}
|
||||
// axe blood
|
||||
ainfo->BloodType3 = blood;
|
||||
defaults->NameVar("BloodType3") = blood;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1413,21 +1278,28 @@ DEFINE_PROPERTY(poisondamagetype, S, Actor)
|
|||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(fastspeed, F, Actor)
|
||||
DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(i, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->FastSpeed = i;
|
||||
defaults->RadiusDamageFactor = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
|
||||
DEFINE_PROPERTY(selfdamagefactor, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(i, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->RDFactor = i;
|
||||
defaults->SelfDamageFactor = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(stealthalpha, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(i, 0);
|
||||
defaults->StealthAlpha = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1436,8 +1308,7 @@ DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
|
|||
DEFINE_PROPERTY(cameraheight, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(i, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->CameraHeight = i;
|
||||
defaults->CameraHeight = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1811,16 +1682,6 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory)
|
|||
defaults->PickupFlash = FindClassTentative(str, RUNTIME_CLASS(AActor));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->PickupMsg = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1855,15 +1716,6 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory)
|
|||
defaults->UseSound = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
|
||||
{
|
||||
PROP_INT_PARM(i, 0);
|
||||
defaults->GiveQuest = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -2698,24 +2550,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
|
|||
bag.DropItemList = di;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
defaults->InvulMode = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
defaults->HealingRadiusType = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
|
|
@ -109,12 +109,18 @@ begin:
|
|||
reg.atag[a] = ATAG_GENERIC; // using ATAG_FRAMEPOINTER will cause endless asserts.
|
||||
NEXTOP;
|
||||
|
||||
OP(META):
|
||||
OP(CLSS):
|
||||
ASSERTA(a); ASSERTO(B);
|
||||
reg.a[a] = ((DObject*)reg.a[B])->GetClass(); // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer...
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
|
||||
OP(META):
|
||||
ASSERTA(a); ASSERTO(B);
|
||||
reg.a[a] = ((DObject*)reg.a[B])->GetClass()->Meta; // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer...
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
|
||||
OP(LB):
|
||||
ASSERTD(a); ASSERTA(B); ASSERTKD(C);
|
||||
GETADDR(PB,KC,X_READ_NIL);
|
||||
|
|
|
@ -23,7 +23,8 @@ xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed
|
|||
xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed
|
||||
xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed
|
||||
xx(LFP, lf, LFP, NOP, 0, 0), // load frame pointer
|
||||
xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta class address
|
||||
xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta data address
|
||||
xx(CLSS, clss, RPRP, NOP, 0, 0), // load a class's descriptor address
|
||||
|
||||
// Load from memory. rA = *(rB + rkC)
|
||||
xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte
|
||||
|
|
|
@ -1007,6 +1007,11 @@ void ZCCCompiler::CompileAllFields()
|
|||
type->Size = Classes[i]->Type()->ParentClass->Size;
|
||||
}
|
||||
}
|
||||
if (Classes[i]->Type()->ParentClass)
|
||||
type->MetaSize = Classes[i]->Type()->ParentClass->MetaSize;
|
||||
else
|
||||
type->MetaSize = 0;
|
||||
|
||||
if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type)))
|
||||
{
|
||||
// Remove from the list if all fields got compiled.
|
||||
|
@ -1070,11 +1075,6 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
if (field->Flags & ZCC_Meta)
|
||||
{
|
||||
varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly
|
||||
if (!(field->Flags & ZCC_Native))
|
||||
{
|
||||
// Non-native meta data is not implemented yet and requires some groundwork in the class copy code.
|
||||
Error(field, "Metadata member %s must be native", FName(field->Names->Name).GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
if (field->Type->ArraySize != nullptr)
|
||||
|
@ -1095,8 +1095,13 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
|
||||
if (varflags & VARF_Native)
|
||||
{
|
||||
auto querytype = (varflags & VARF_Meta) ? type->GetClass() : type;
|
||||
fd = FindField(querytype, FName(name->Name).GetChars());
|
||||
if (varflags & VARF_Meta)
|
||||
{
|
||||
Error(field, "Native meta variable %s not allowed", FName(name->Name).GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = FindField(type, FName(name->Name).GetChars());
|
||||
if (fd == nullptr)
|
||||
{
|
||||
Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars());
|
||||
|
@ -1113,6 +1118,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hasnativechildren)
|
||||
{
|
||||
Error(field, "Cannot add field %s to %s. %s has native children which means it size may not change.", FName(name->Name).GetChars(), type->TypeName.GetChars(), type->TypeName.GetChars());
|
||||
|
@ -1188,8 +1194,10 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Proper
|
|||
FString qualifiedname;
|
||||
// Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen.
|
||||
// All these will be removed from the symbol table after the compiler finishes to free up the allocated space.
|
||||
if (prefix == NAME_None) qualifiedname.Format("@property@%s", FName(p->NodeName).GetChars());
|
||||
else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), FName(p->NodeName).GetChars());
|
||||
FName name = FName(p->NodeName);
|
||||
if (prefix == NAME_None) qualifiedname.Format("@property@%s", name.GetChars());
|
||||
else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), name.GetChars());
|
||||
|
||||
fields.ShrinkToFit();
|
||||
if (!type->Symbols.AddSymbol(new PProperty(qualifiedname, fields)))
|
||||
{
|
||||
|
@ -1692,7 +1700,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
|
|||
|
||||
if (f->Flags & VARF_Meta)
|
||||
{
|
||||
addr = ((char*)bag.Info) + f->Offset;
|
||||
addr = ((char*)bag.Info->Meta) + f->Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -281,6 +281,7 @@ static void ParseSingleFile(const char *filename, int lump, void *parser, ZCCPar
|
|||
tokentype = ZCC_FLOATCONST;
|
||||
break;
|
||||
|
||||
case TK_None: // 'NONE' is a token for SBARINFO but not here.
|
||||
case TK_Identifier:
|
||||
value.Int = FName(sc.String);
|
||||
tokentype = ZCC_IDENTIFIER;
|
||||
|
|
|
@ -486,6 +486,8 @@ bool FSerializer::OpenReader(FCompressedBuffer *input)
|
|||
|
||||
void FSerializer::Close()
|
||||
{
|
||||
if (w == nullptr && r == nullptr) return; // double close? This should skip the I_Error at the bottom.
|
||||
|
||||
if (w != nullptr)
|
||||
{
|
||||
delete w;
|
||||
|
@ -590,7 +592,7 @@ bool FSerializer::BeginObject(const char *name)
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Object expected for '%s'", name);
|
||||
Printf(TEXTCOLOR_RED "Object expected for '%s'\n", name);
|
||||
mErrors++;
|
||||
return false;
|
||||
}
|
||||
|
@ -656,7 +658,7 @@ bool FSerializer::BeginArray(const char *name)
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Array expected for '%s'", name);
|
||||
Printf(TEXTCOLOR_RED "Array expected for '%s'\n", name);
|
||||
mErrors++;
|
||||
return false;
|
||||
}
|
||||
|
@ -748,7 +750,7 @@ FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int spe
|
|||
else
|
||||
{
|
||||
assert(false && "Integer expected");
|
||||
Printf(TEXTCOLOR_RED "Integer expected for '%s[%d]'", key, i);
|
||||
Printf(TEXTCOLOR_RED "Integer expected for '%s[%d]'\n", key, i);
|
||||
mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -756,7 +758,7 @@ FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int spe
|
|||
else
|
||||
{
|
||||
assert(false && "array expected");
|
||||
Printf(TEXTCOLOR_RED "array expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "array expected for '%s'\n", key);
|
||||
mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -800,7 +802,7 @@ FSerializer &FSerializer::ScriptNum(const char *key, int &num)
|
|||
else
|
||||
{
|
||||
assert(false && "Integer expected");
|
||||
Printf(TEXTCOLOR_RED "Integer expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "Integer expected for '%s'\n", key);
|
||||
mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -1005,7 +1007,7 @@ void FSerializer::ReadObjects(bool hubtravel)
|
|||
PClass *cls = PClass::FindClass(clsname);
|
||||
if (cls == nullptr)
|
||||
{
|
||||
Printf("Unknown object class '%s' in savegame", clsname.GetChars());
|
||||
Printf(TEXTCOLOR_RED "Unknown object class '%s' in savegame\n", clsname.GetChars());
|
||||
founderrors = true;
|
||||
r->mDObjects[i] = RUNTIME_CLASS(AActor)->CreateNew(); // make sure we got at least a valid pointer for the duration of the loading process.
|
||||
r->mDObjects[i]->Destroy(); // but we do not want to keep this around, so destroy it right away.
|
||||
|
@ -1041,7 +1043,7 @@ void FSerializer::ReadObjects(bool hubtravel)
|
|||
catch (CRecoverableError &err)
|
||||
{
|
||||
// In case something in here throws an error, let's continue and deal with it later.
|
||||
Printf(TEXTCOLOR_RED "'%s'\n while restoring %s", err.GetMessage(), obj ? obj->GetClass()->TypeName.GetChars() : "invalid object");
|
||||
Printf(TEXTCOLOR_RED "'%s'\n while restoring %s\n", err.GetMessage(), obj ? obj->GetClass()->TypeName.GetChars() : "invalid object");
|
||||
mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -1055,7 +1057,7 @@ void FSerializer::ReadObjects(bool hubtravel)
|
|||
assert(!founderrors);
|
||||
if (founderrors)
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Failed to restore all objects in savegame");
|
||||
Printf(TEXTCOLOR_RED "Failed to restore all objects in savegame\n");
|
||||
mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -1064,7 +1066,7 @@ void FSerializer::ReadObjects(bool hubtravel)
|
|||
// nuke all objects we created here.
|
||||
for (auto obj : r->mDObjects)
|
||||
{
|
||||
obj->Destroy();
|
||||
if (!(obj->ObjectFlags & OF_EuthanizeMe)) obj->Destroy();
|
||||
}
|
||||
r->mDObjects.Clear();
|
||||
|
||||
|
@ -1182,7 +1184,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *def
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "boolean type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "boolean type expected for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -1218,7 +1220,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, int64_t &value, int64_
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "integer type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -1254,7 +1256,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, uint64_t &value, uint6
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "integer type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -1291,7 +1293,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, int32_t &value, int32_
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "integer type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -1327,7 +1329,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, uint32_t &value, uint3
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "integer type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "integer type expected for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -1405,7 +1407,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "float type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "float type expected for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -1548,7 +1550,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'\n", key);
|
||||
value.SetNull();
|
||||
arc.mErrors++;
|
||||
}
|
||||
|
@ -1564,7 +1566,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe
|
|||
else
|
||||
{
|
||||
assert(false && "not a texture");
|
||||
Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "object does not represent a texture for '%s'\n", key);
|
||||
value.SetNull();
|
||||
arc.mErrors++;
|
||||
}
|
||||
|
@ -1649,7 +1651,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObje
|
|||
else
|
||||
{
|
||||
assert(false && "invalid object reference");
|
||||
Printf(TEXTCOLOR_RED "Invalid object reference for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "Invalid object reference for '%s'\n", key);
|
||||
value = nullptr;
|
||||
arc.mErrors++;
|
||||
if (retcode) *retcode = false;
|
||||
|
@ -1698,7 +1700,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "String expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "String expected for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
value = NAME_None;
|
||||
}
|
||||
|
@ -1746,7 +1748,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDynamicCol
|
|||
}
|
||||
}
|
||||
assert(false && "not a colormap");
|
||||
Printf(TEXTCOLOR_RED "object does not represent a colormap for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "object does not represent a colormap for '%s'\n", key);
|
||||
cm = &NormalLight;
|
||||
}
|
||||
}
|
||||
|
@ -1787,7 +1789,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "string type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key);
|
||||
sid = 0;
|
||||
arc.mErrors++;
|
||||
}
|
||||
|
@ -1836,7 +1838,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "string type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key);
|
||||
clst = nullptr;
|
||||
arc.mErrors++;
|
||||
}
|
||||
|
@ -1884,7 +1886,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&cl
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "string type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "string type expected for '%s'\n", key);
|
||||
clst = nullptr;
|
||||
arc.mErrors++;
|
||||
}
|
||||
|
@ -1960,20 +1962,20 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState
|
|||
{
|
||||
// this can actually happen by changing the DECORATE so treat it as a warning, not an error.
|
||||
state = nullptr;
|
||||
Printf(TEXTCOLOR_ORANGE "Invalid state '%s+%d' for '%s'", cls.GetString(), ndx.GetInt(), key);
|
||||
Printf(TEXTCOLOR_ORANGE "Invalid state '%s+%d' for '%s'\n", cls.GetString(), ndx.GetInt(), key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false && "not a state");
|
||||
Printf(TEXTCOLOR_RED "data does not represent a state for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "data does not represent a state for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
}
|
||||
}
|
||||
else if (!retcode)
|
||||
{
|
||||
assert(false && "not an array");
|
||||
Printf(TEXTCOLOR_RED "array type expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "array type expected for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
}
|
||||
}
|
||||
|
@ -2028,7 +2030,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDial
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "integer expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "integer expected for '%s'\n", key);
|
||||
arc.mErrors++;
|
||||
node = nullptr;
|
||||
}
|
||||
|
@ -2077,7 +2079,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&p
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "string expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "string expected for '%s'\n", key);
|
||||
pstr = nullptr;
|
||||
arc.mErrors++;
|
||||
}
|
||||
|
@ -2119,7 +2121,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FString &pstr, FString
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "string expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "string expected for '%s'\n", key);
|
||||
pstr = "";
|
||||
arc.mErrors++;
|
||||
}
|
||||
|
@ -2168,7 +2170,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr
|
|||
}
|
||||
else
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "string expected for '%s'", key);
|
||||
Printf(TEXTCOLOR_RED "string expected for '%s'\n", key);
|
||||
pstr = nullptr;
|
||||
arc.mErrors++;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
|
||||
~FSerializer()
|
||||
{
|
||||
mErrors = 0; // The destructor may not throw an exception so silence the error checker.
|
||||
Close();
|
||||
}
|
||||
bool OpenWriter(bool pretty = true);
|
||||
|
|
|
@ -57,7 +57,7 @@ const char *GetVersionString();
|
|||
// Version identifier for network games.
|
||||
// Bump it every time you do a release unless you're certain you
|
||||
// didn't change anything that will affect sync.
|
||||
#define NETGAMEVERSION 232
|
||||
#define NETGAMEVERSION 233
|
||||
|
||||
// Version stored in the ini's [LastRun] section.
|
||||
// Bump it if you made some configuration change that you want to
|
||||
|
|
|
@ -393,7 +393,6 @@ void FString::Remove(size_t index, size_t remlen)
|
|||
}
|
||||
else
|
||||
{
|
||||
remlen = Len() - remlen < remlen ? Len() - remlen : remlen;
|
||||
if (Data()->RefCount == 1)
|
||||
{ // Can do this in place
|
||||
memmove(Chars + index, Chars + index + remlen, Len() - index - remlen);
|
||||
|
|
|
@ -497,6 +497,12 @@ ABC4EB5A1535ECCD0061AD14F3547908 // Plutonia Experiment, map26
|
|||
setsectorspecial 156 0
|
||||
}
|
||||
|
||||
B68EB7CFB4CC481796E2919B9C16DFBD // Moc11.wad e1m6
|
||||
{
|
||||
setvertex 1650 -3072 2671
|
||||
setvertex 1642 -2944 2671
|
||||
}
|
||||
|
||||
712BB4CFBD0753178CA0C6814BE4C288 // map12 BTSX_E1 - patch some rendering glitches that are problematic to detect
|
||||
{
|
||||
setsectortag 545 32000
|
||||
|
|
|
@ -106,7 +106,6 @@ CMPTMNU_RENDERINGBEHAVIOR = "Rendering Behaviour";
|
|||
CMPTMNU_SOUNDBEHAVIOR = "Sound Behaviour";
|
||||
CMPTMNU_SECTORSOUNDS = "Sector sounds use centre as source";
|
||||
OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colours only";
|
||||
OPTVAL_NODOORS = "All except doors";
|
||||
C_GRAY = "\ccgrey";
|
||||
C_DARKGRAY = "\cudark grey";
|
||||
|
||||
|
|
|
@ -2286,6 +2286,7 @@ OPTVAL_FRONT = "Front";
|
|||
OPTVAL_ANIMATED = "Animated";
|
||||
OPTVAL_ROTATED = "Rotated";
|
||||
OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colors only";
|
||||
OPTVAL_NODOORS = "All except doors";
|
||||
OPTVAL_DOUBLE = "Double";
|
||||
OPTVAL_TRIPLE = "Triple";
|
||||
OPTVAL_QUADRUPLE = "Quadruple";
|
||||
|
|
|
@ -638,6 +638,7 @@ OptionValue PuffTypes
|
|||
{
|
||||
0.0, "$OPTVAL_SPRITES"
|
||||
1.0, "$OPTVAL_PARTICLES"
|
||||
2.0, "$OPTVAL_SPRITESPARTICLES"
|
||||
}
|
||||
|
||||
OptionValue Wipes
|
||||
|
@ -1013,7 +1014,7 @@ OptionValue MapBackTypes
|
|||
OptionValue MapTriggers
|
||||
{
|
||||
0, "$OPTVAL_OFF"
|
||||
1, "$OPTVAL_NO_DOORS"
|
||||
1, "$OPTVAL_NODOORS"
|
||||
2, "$OPTVAL_ON"
|
||||
}
|
||||
|
||||
|
|
|
@ -189,29 +189,48 @@ class Actor : Thinker native
|
|||
native State MissileState;
|
||||
native voidptr /*DecalBase*/ DecalGenerator;
|
||||
native uint8 fountaincolor;
|
||||
native double CameraHeight; // Height of camera when used as such
|
||||
native double RadiusDamageFactor; // Radius damage factor
|
||||
native double SelfDamageFactor;
|
||||
native double StealthAlpha;
|
||||
native int WoundHealth; // Health needed to enter wound state
|
||||
native readonly color BloodColor;
|
||||
native readonly int BloodTranslation;
|
||||
|
||||
native meta String Obituary; // Player was killed by this actor
|
||||
native meta String HitObituary; // Player was killed by this actor in melee
|
||||
native meta double DeathHeight; // Height on normal death
|
||||
native meta double BurnHeight; // Height on burning death
|
||||
native meta color BloodColor; // Colorized blood
|
||||
native meta int GibHealth; // Negative health below which this monster dies an extreme death
|
||||
native meta int WoundHealth; // Health needed to enter wound state
|
||||
native meta double FastSpeed; // speed in fast mode
|
||||
native meta double RDFactor; // Radius damage factor
|
||||
native meta double CameraHeight; // Height of camera when used as such
|
||||
native meta Sound HowlSound; // Sound being played when electrocuted or poisoned
|
||||
native meta Name BloodType; // Blood replacement type
|
||||
native meta Name BloodType2; // Bloopsplatter replacement type
|
||||
native meta Name BloodType3; // AxeBlood replacement type
|
||||
native meta bool DontHurtShooter;
|
||||
native meta int ExplosionRadius;
|
||||
native meta int ExplosionDamage;
|
||||
native meta int MeleeDamage;
|
||||
native meta Sound MeleeSound;
|
||||
native meta Name MissileName;
|
||||
native meta double MissileHeight;
|
||||
meta String Obituary; // Player was killed by this actor
|
||||
meta String HitObituary; // Player was killed by this actor in melee
|
||||
meta double DeathHeight; // Height on normal death
|
||||
meta double BurnHeight; // Height on burning death
|
||||
meta int GibHealth; // Negative health below which this monster dies an extreme death
|
||||
meta Sound HowlSound; // Sound being played when electrocuted or poisoned
|
||||
meta Name BloodType; // Blood replacement type
|
||||
meta Name BloodType2; // Bloopsplatter replacement type
|
||||
meta Name BloodType3; // AxeBlood replacement type
|
||||
meta bool DontHurtShooter;
|
||||
meta int ExplosionRadius;
|
||||
meta int ExplosionDamage;
|
||||
meta int MeleeDamage;
|
||||
meta Sound MeleeSound;
|
||||
meta double MissileHeight;
|
||||
meta Name MissileName;
|
||||
meta double FastSpeed; // speed in fast mode
|
||||
|
||||
Property prefix: none;
|
||||
Property Obituary: Obituary;
|
||||
Property HitObituary: HitObituary;
|
||||
Property MeleeDamage: MeleeDamage;
|
||||
Property MeleeSound: MeleeSound;
|
||||
Property MissileHeight: MissileHeight;
|
||||
Property MissileType: MissileName;
|
||||
Property DontHurtShooter: DontHurtShooter;
|
||||
Property ExplosionRadius: ExplosionRadius;
|
||||
Property ExplosionDamage: ExplosionDamage;
|
||||
//Property BloodType: BloodType, BloodType2, BloodType3;
|
||||
Property FastSpeed: FastSpeed;
|
||||
Property HowlSound: HowlSound;
|
||||
Property GibHealth: GibHealth;
|
||||
Property DeathHeight: DeathHeight;
|
||||
Property BurnHeight: BurnHeight;
|
||||
|
||||
// need some definition work first
|
||||
//FRenderStyle RenderStyle;
|
||||
|
@ -271,6 +290,7 @@ class Actor : Thinker native
|
|||
DefThreshold 100;
|
||||
BloodType "Blood", "BloodSplatter", "AxeBlood";
|
||||
ExplosionDamage 128;
|
||||
ExplosionRadius -1; // i.e. use ExplosionDamage value
|
||||
MissileHeight 32;
|
||||
SpriteAngle 0;
|
||||
SpriteRotation 0;
|
||||
|
@ -278,6 +298,15 @@ class Actor : Thinker native
|
|||
VisibleAngles 0, 0;
|
||||
VisiblePitch 0, 0;
|
||||
DefaultStateUsage SUF_ACTOR|SUF_OVERLAY;
|
||||
CameraHeight int.min;
|
||||
FastSpeed -1;
|
||||
RadiusDamageFactor 1;
|
||||
SelfDamageFactor 1;
|
||||
StealthAlpha 0;
|
||||
WoundHealth 6;
|
||||
GibHealth int.min;
|
||||
DeathHeight -1;
|
||||
BurnHeight -1;
|
||||
}
|
||||
|
||||
// Functions
|
||||
|
@ -310,7 +339,7 @@ class Actor : Thinker native
|
|||
virtual native void Touch(Actor toucher);
|
||||
virtual native void MarkPrecacheSounds();
|
||||
|
||||
// Called by PIT_CheckThing to check if two actos actually can collide.
|
||||
// Called by PIT_CheckThing to check if two actors actually can collide.
|
||||
virtual bool CanCollideWith(Actor other, bool passive)
|
||||
{
|
||||
return true;
|
||||
|
@ -335,6 +364,81 @@ class Actor : Thinker native
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual class<Actor> GetBloodType(int type)
|
||||
{
|
||||
Class<Actor> bloodcls;
|
||||
if (type == 0)
|
||||
{
|
||||
bloodcls = BloodType;
|
||||
}
|
||||
else if (type == 1)
|
||||
{
|
||||
bloodcls = BloodType2;
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
bloodcls = BloodType3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bloodcls != NULL)
|
||||
{
|
||||
bloodcls = GetReplacement(bloodcls);
|
||||
}
|
||||
return bloodcls;
|
||||
}
|
||||
|
||||
virtual int GetGibHealth()
|
||||
{
|
||||
if (GibHealth != int.min)
|
||||
{
|
||||
return -abs(GibHealth);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -int(GetSpawnHealth() * gameinfo.gibfactor);
|
||||
}
|
||||
}
|
||||
|
||||
virtual double GetDeathHeight()
|
||||
{
|
||||
// [RH] Allow the death height to be overridden using metadata.
|
||||
double metaheight = -1;
|
||||
if (DamageType == 'Fire')
|
||||
{
|
||||
metaheight = BurnHeight;
|
||||
}
|
||||
if (metaheight < 0)
|
||||
{
|
||||
metaheight = DeathHeight;
|
||||
}
|
||||
if (metaheight < 0)
|
||||
{
|
||||
return Height * 0.25;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MAX(metaheight, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
|
||||
{
|
||||
if (mod == 'Telefrag')
|
||||
{
|
||||
return "$OB_MONTELEFRAG";
|
||||
}
|
||||
else if (mod == 'Melee' && HitObituary.Length() > 0)
|
||||
{
|
||||
return HitObituary;
|
||||
}
|
||||
return Obituary;
|
||||
}
|
||||
|
||||
|
||||
native static class<Actor> GetReplacement(class<Actor> cls);
|
||||
native static class<Actor> GetReplacee(class<Actor> cls);
|
||||
native static int GetSpriteIndex(name sprt);
|
||||
|
@ -510,7 +614,6 @@ class Actor : Thinker native
|
|||
native double GetAngle(int flags, int ptr = AAPTR_TARGET);
|
||||
native double GetZAt(double px = 0, double py = 0, double angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT);
|
||||
native int GetSpawnHealth();
|
||||
native int GetGibHealth();
|
||||
native double GetCrouchFactor(int ptr = AAPTR_PLAYER1);
|
||||
native double GetCVar(string cvar);
|
||||
native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT);
|
||||
|
@ -725,6 +828,68 @@ class Actor : Thinker native
|
|||
native bool A_LineEffect(int boomspecial = 0, int tag = 0);
|
||||
// End of MBF redundant functions.
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// old customizable attack functions which use actor parameters.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
private void DoAttack (bool domelee, bool domissile, int MeleeDamage, Sound MeleeSound, Class<Actor> MissileType,double MissileHeight)
|
||||
{
|
||||
if (target == NULL) return;
|
||||
|
||||
A_FaceTarget ();
|
||||
if (domelee && MeleeDamage>0 && CheckMeleeRange ())
|
||||
{
|
||||
int damage = random[CustomMelee](1, 8) * MeleeDamage;
|
||||
if (MeleeSound) A_PlaySound (MeleeSound, CHAN_WEAPON);
|
||||
int newdam = target.DamageMobj (self, self, damage, 'Melee');
|
||||
target.TraceBleed (newdam > 0 ? newdam : damage, self);
|
||||
}
|
||||
else if (domissile && MissileType != NULL)
|
||||
{
|
||||
// This seemingly senseless code is needed for proper aiming.
|
||||
double add = MissileHeight + GetBobOffset() - 32;
|
||||
AddZ(add);
|
||||
Actor missile = SpawnMissileXYZ (Pos + (0, 0, 32), target, MissileType, false);
|
||||
AddZ(-add);
|
||||
|
||||
if (missile)
|
||||
{
|
||||
// automatic handling of seeker missiles
|
||||
if (missile.bSeekerMissile)
|
||||
{
|
||||
missile.tracer = target;
|
||||
}
|
||||
missile.CheckMissileSpawn(radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deprecated void A_MeleeAttack()
|
||||
{
|
||||
DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0);
|
||||
}
|
||||
|
||||
deprecated void A_MissileAttack()
|
||||
{
|
||||
Class<Actor> MissileType = MissileName;
|
||||
DoAttack(false, true, 0, 0, MissileType, MissileHeight);
|
||||
}
|
||||
|
||||
deprecated void A_ComboAttack()
|
||||
{
|
||||
Class<Actor> MissileType = MissileName;
|
||||
DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight);
|
||||
}
|
||||
|
||||
void A_BasicAttack(int melee_damage, sound melee_sound, class<actor> missile_type, double missile_height)
|
||||
{
|
||||
DoAttack(true, true, melee_damage, melee_sound, missile_type, missile_height);
|
||||
}
|
||||
|
||||
|
||||
native void A_MonsterRail();
|
||||
native void A_Pain();
|
||||
native void A_NoBlocking(bool drop = true);
|
||||
|
@ -753,9 +918,6 @@ class Actor : Thinker native
|
|||
native void A_Wander(int flags = 0);
|
||||
native void A_Look2();
|
||||
|
||||
deprecated native void A_MissileAttack();
|
||||
deprecated native void A_MeleeAttack();
|
||||
deprecated native void A_ComboAttack();
|
||||
deprecated 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");
|
||||
native 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);
|
||||
|
@ -793,7 +955,6 @@ class Actor : Thinker native
|
|||
native void A_RaiseMaster(int flags = 0);
|
||||
native void A_RaiseChildren(int flags = 0);
|
||||
native void A_RaiseSiblings(int flags = 0);
|
||||
deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class<actor> missiletype, double missileheight);
|
||||
action native bool, Actor A_ThrowGrenade(class<Actor> itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true);
|
||||
native void A_Weave(int xspeed, int yspeed, double xdist, double ydist);
|
||||
native bool A_Morph(class<Actor> type, int duration = 0, int flags = 0, class<Actor> enter_flash = null, class<Actor> exit_flash = null);
|
||||
|
|
|
@ -310,6 +310,7 @@ struct GameInfoStruct native
|
|||
native GIFont mStatscreenMapNameFont;
|
||||
native GIFont mStatscreenEnteringFont;
|
||||
native GIFont mStatscreenFinishedFont;
|
||||
native double gibfactor;
|
||||
}
|
||||
|
||||
class Object native
|
||||
|
|
|
@ -1005,6 +1005,13 @@ enum ERaise
|
|||
RF_NOCHECKPOSITION = 2
|
||||
}
|
||||
|
||||
enum eFogParm
|
||||
{
|
||||
FOGP_DENSITY = 0,
|
||||
FOGP_OUTSIDEDENSITY = 1,
|
||||
FOGP_SKYFOG = 2,
|
||||
}
|
||||
|
||||
enum ETeleport
|
||||
{
|
||||
TELF_DESTFOG = 1,
|
||||
|
|
|
@ -72,6 +72,8 @@ class Megasphere : CustomInventory
|
|||
{
|
||||
+COUNTITEM
|
||||
+INVENTORY.ALWAYSPICKUP
|
||||
+INVENTORY.ISHEALTH
|
||||
+INVENTORY.ISARMOR
|
||||
Inventory.PickupMessage "$GOTMSPHERE";
|
||||
Inventory.PickupSound "misc/p_pkup";
|
||||
}
|
||||
|
@ -183,6 +185,7 @@ class Berserk : CustomInventory
|
|||
{
|
||||
+COUNTITEM
|
||||
+INVENTORY.ALWAYSPICKUP
|
||||
+INVENTORY.ISHEALTH
|
||||
Inventory.PickupMessage "$GOTBERSERK";
|
||||
Inventory.PickupSound "misc/p_pkup";
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class Ammo : Inventory
|
|||
{
|
||||
int BackpackAmount;
|
||||
int BackpackMaxAmount;
|
||||
/*meta*/ int DropAmount;
|
||||
meta int DropAmount;
|
||||
|
||||
property BackpackAmount: BackpackAmount;
|
||||
property BackpackMaxAmount: BackpackMaxAmount;
|
||||
|
|
|
@ -38,6 +38,7 @@ class Armor : Inventory
|
|||
Default
|
||||
{
|
||||
Inventory.PickupSound "misc/armor_pkup";
|
||||
+INVENTORY.ISARMOR
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,13 +36,14 @@
|
|||
class Health : Inventory
|
||||
{
|
||||
transient int PrevHealth;
|
||||
/*meta*/ int LowHealth;
|
||||
/*meta*/ String LowHealthMessage;
|
||||
meta int LowHealth;
|
||||
meta String LowHealthMessage;
|
||||
|
||||
property LowMessage: LowHealth, LowHealthMessage;
|
||||
|
||||
Default
|
||||
{
|
||||
+INVENTORY.ISHEALTH
|
||||
Inventory.Amount 1;
|
||||
Inventory.MaxAmount 0;
|
||||
Inventory.PickupSound "misc/health_pkup";
|
||||
|
@ -85,8 +86,36 @@ class Health : Inventory
|
|||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class MaxHealth : Health
|
||||
{
|
||||
//===========================================================================
|
||||
//
|
||||
// TryPickup
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override bool TryPickup (in out Actor other)
|
||||
{
|
||||
bool success = false;
|
||||
int savedAmount = MaxAmount;
|
||||
let player = PlayerPawn(other);
|
||||
MaxAmount = Health;
|
||||
if (player)
|
||||
{
|
||||
if (player.BonusHealth < savedAmount)
|
||||
{
|
||||
player.BonusHealth = min(player.BonusHealth + Amount, savedAmount);
|
||||
success = true;
|
||||
}
|
||||
MaxAmount += player.BonusHealth;
|
||||
}
|
||||
success |= Super.TryPickup(other);
|
||||
MaxAmount = savedAmount;
|
||||
if (success) GoAwayAndDie();
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
class HealthPickup : Inventory
|
||||
|
@ -99,6 +128,7 @@ class HealthPickup : Inventory
|
|||
{
|
||||
Inventory.DefMaxAmount;
|
||||
+INVENTORY.INVBAR
|
||||
+INVENTORY.ISHEALTH
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -87,8 +87,8 @@ class MapRevealer : Inventory
|
|||
|
||||
class PuzzleItem : Inventory
|
||||
{
|
||||
/*meta*/ int PuzzleItemNumber;
|
||||
/*meta*/ String PuzzFailMessage;
|
||||
meta int PuzzleItemNumber;
|
||||
meta String PuzzFailMessage;
|
||||
|
||||
property Number: PuzzleItemNumber;
|
||||
property FailMessage: PuzzFailMessage;
|
||||
|
|
|
@ -23,8 +23,11 @@ class Inventory : Actor native
|
|||
native bool bPickupGood;
|
||||
native bool bCreateCopyMoved;
|
||||
native bool bInitEffectFailed;
|
||||
native meta String PickupMsg;
|
||||
native /*meta*/ int GiveQuest;
|
||||
meta String PickupMsg;
|
||||
meta int GiveQuest;
|
||||
|
||||
Property PickupMessage: PickupMsg;
|
||||
Property GiveQuest: GiveQuest;
|
||||
|
||||
Default
|
||||
{
|
||||
|
|
|
@ -33,7 +33,7 @@ class Weapon : StateProvider native
|
|||
native float FOVScale;
|
||||
native int Crosshair; // 0 to use player's crosshair
|
||||
native bool GivenAsMorphWeapon;
|
||||
native bool bAltFire; // Set when self weapon's alternate fire is used.
|
||||
native bool bAltFire; // Set when this weapon's alternate fire is used.
|
||||
native readonly bool bDehAmmo;
|
||||
|
||||
Default
|
||||
|
@ -89,6 +89,12 @@ class Weapon : StateProvider native
|
|||
return s;
|
||||
}
|
||||
|
||||
override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
|
||||
{
|
||||
// Weapons may never return HitObituary by default. Override this if it is needed.
|
||||
return Obituary;
|
||||
}
|
||||
|
||||
action void A_GunFlash(statelabel flashlabel = null, int flags = 0)
|
||||
{
|
||||
let player = player;
|
||||
|
|
|
@ -3,22 +3,19 @@ class PlayerPawn : Actor native
|
|||
|
||||
native int crouchsprite;
|
||||
native int MaxHealth;
|
||||
native int BonusHealth;
|
||||
native int MugShotMaxHealth;
|
||||
native int RunHealth;
|
||||
native int PlayerFlags;
|
||||
native Inventory InvFirst; // first inventory item displayed on inventory bar
|
||||
native Inventory InvSel; // selected inventory item
|
||||
native meta String DisplayName; // Display name (used in menus, etc.)
|
||||
|
||||
native /*meta*/ Name SoundClass; // Sound class
|
||||
native /*meta*/ Name Face; // Doom status bar face (when used)
|
||||
native /*meta*/ Name Portrait;
|
||||
native /*meta*/ Name Slot[10];
|
||||
native /*meta*/ Name InvulMode;
|
||||
native /*meta*/ Name HealingRadiusType;
|
||||
native /*meta*/ double HexenArmor[5];
|
||||
native /*meta*/ uint8 ColorRangeStart; // Skin color range
|
||||
native /*meta*/ uint8 ColorRangeEnd;
|
||||
native Name SoundClass; // Sound class
|
||||
native Name Face; // Doom status bar face (when used)
|
||||
native Name Portrait;
|
||||
native Name Slot[10];
|
||||
native double HexenArmor[5];
|
||||
native uint8 ColorRangeStart; // Skin color range
|
||||
native uint8 ColorRangeEnd;
|
||||
|
||||
// [GRB] Player class properties
|
||||
native double JumpZ;
|
||||
|
@ -38,6 +35,13 @@ class PlayerPawn : Actor native
|
|||
native double ViewBob; // [SP] ViewBob Multiplier
|
||||
native double FullHeight;
|
||||
|
||||
meta Name HealingRadiusType;
|
||||
meta Name InvulMode;
|
||||
|
||||
Property prefix: Player;
|
||||
Property HealRadiusType: HealingradiusType;
|
||||
Property InvulnerabilityMode: InvulMode;
|
||||
|
||||
Default
|
||||
{
|
||||
Health 100;
|
||||
|
@ -115,6 +119,36 @@ class PlayerPawn : Actor native
|
|||
}
|
||||
}
|
||||
|
||||
override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
|
||||
{
|
||||
if (victim.player != player && victim.IsTeammate(self))
|
||||
{
|
||||
victim = self;
|
||||
return String.Format("$OB_FRIENDLY%c", random[Obituary](49, 53));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mod == 'Telefrag') return "$OB_MPTELEFRAG";
|
||||
|
||||
String message;
|
||||
if (inflictor != NULL)
|
||||
{
|
||||
message = inflictor.GetObituary(victim, inflictor, mod, playerattack);
|
||||
}
|
||||
if (message.Length() == 0 && playerattack && player.ReadyWeapon != NULL)
|
||||
{
|
||||
message = player.ReadyWeapon.GetObituary(victim, inflictor, mod, playerattack);
|
||||
}
|
||||
if (message.Length() == 0)
|
||||
{
|
||||
if (mod == 'BFGSplash') return "$OB_MPBFG_SPLASH";
|
||||
if (mod == 'Railgun') return "$OB_RAILGUN";
|
||||
message = Obituary;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
// This is for SBARINFO.
|
||||
int, int GetEffectTicsForItem(class<Inventory> item)
|
||||
{
|
||||
|
@ -133,7 +167,7 @@ class PlayerPawn : Actor native
|
|||
return -1, -1;
|
||||
}
|
||||
|
||||
native int GetMaxHealth();
|
||||
native int GetMaxHealth(bool withupgrades = false);
|
||||
native bool ResetAirSupply (bool playgasp = false);
|
||||
native void CheckWeaponSwitch(class<Inventory> item);
|
||||
native static String GetPrintableDisplayName(Class<Actor> cls);
|
||||
|
@ -320,6 +354,7 @@ usercmd_t original_cmd;
|
|||
native int GetGender();
|
||||
native int GetTeam();
|
||||
native float GetAutoaim();
|
||||
native void SetFOV(float fov);
|
||||
}
|
||||
|
||||
struct PlayerClass native
|
||||
|
|
|
@ -76,7 +76,7 @@ extend class PlayerPawn
|
|||
}
|
||||
else
|
||||
{
|
||||
player.health = health = GetMaxHealth();
|
||||
player.health = health = GetMaxHealth(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ class Programmer : Actor
|
|||
A_PlaySound("programmer/clank", CHAN_WEAPON);
|
||||
|
||||
int damage = ((random[Programmer]() % 10) + 1) * 6;
|
||||
int newdam = DamageMobj (self, self, damage, 'Melee');
|
||||
int newdam = target.DamageMobj (self, self, damage, 'Melee');
|
||||
target.TraceBleed (newdam > 0 ? newdam : damage, self);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue